【Swift】 クロージャーで呼び出し元 struct のプロパティを更新する
カスタム Struct の例
自身または更新させたいプロパティを参照で渡す関数を定義する。
protocol Editable {}
extension Editable {
mutating func edit( _ editor: ( inout Self ) -> Void ) {
editor(&self)
}
}
struct SomeParent {
var child: SomeChild = SomeChild(
val: 1
)
}
struct SomeChild: Editable {
var val: Int
}
var parent = SomeParent()
parent.child.edit {
$0.val += 1
}
print(parent.child.val) // 2 を出力
Array の例
要素を参照で渡す関数を定義する。
extension Array {
mutating func updateEach( _ updater: ( inout Element ) -> Void ) {
for i in 0..<self.count {
updater(&self[i])
}
}
}
var array = [1, 2, 3, 4, 5]
array.updateEach {
$0 += 1
}
print(array) // [2, 3, 4, 5, 6]
部分的な更新
fatalError の代わりに throw する例外を用意しておく
extension Array {
enum ArrayError: Error, LocalizedError {
case indexOutOfBounds( index: Int )
case invalidRange( range: Range<Index>)
case invalidClosedRange( range: ClosedRange<Index>)
var errorDescription: String? {
switch self {
case .indexOutOfBounds( let index ):
return "Index out of bounds: \(index)"
case .invalidRange( let range ):
return "Invalid range: \(range)"
case .invalidClosedRange( let range ):
return "Invalid range: \(range)"
}
}
}
}
Index 指定
extension Array {
mutating func update( index: Int, _ updater: ( inout Element ) -> Void ) throws {
guard self.indices.contains(index) else {
throw Array.ArrayError.indexOutOfBounds(index: index)
}
updater(&self[index])
}
}
var array = [1, 2, 3, 4, 5]
try array.update( index: 2 ) {
$0 += 10
}
print(array) // [1, 2, 13, 4, 5]
Range ( n..<m ) 指定
extension Array {
mutating func update( range: Range<Index>, _ updater: ( inout Element ) -> Void ) throws {
guard self.indices.contains(range) else {
throw Array.ArrayError.invalidRange(range: range)
}
for i in range {
updater(&self[i])
}
}
}
try array.update(range: 1..<3) {
$0 += 20
}
print(array) // [1, 22, 23, 4, 5]
ClosedRange ( n...m ) 指定
extension Array {
mutating func update( range: ClosedRange<Index>, _ updater: ( inout Element ) -> Void ) throws {
guard self.indices.contains(range) else {
throw Array.ArrayError.invalidClosedRange(range: range)
}
for i in range {
updater(&self[i])
}
}
}
try array.update(range: 1...3) {
$0 += 30
}
print(array) // [1, 32, 33, 34, 5]
Dictionaryの例
Arrayと同様、Valueを参照で渡す関数を定義する。
extension Dictionary {
mutating func updateEach( _ updater: ( inout Value ) -> Void ) {
for key in self.keys {
updater(&self[key]!)
}
}
}
var dic = [
"1" : 1,
"2" : 2,
]
dic.updateEach {
$0 += 1
}
print(dic) // ["2": 3, "1": 2]
Key 指定
extension Dictionary {
mutating func update( key: Key, _ updater: ( inout Value ) -> Void ) {
guard keys.contains(key) else {
return
}
updater(&self[key]!)
}
}
var dic = [
"1" : 1,
"2" : 2,
]
dic.update(key: "1") {
$0 += 100
}
print(dic) // ["1": 101, "2": 2]