Swift と Kotlin を行ったり来たりして開発していると、うーってなることが結構あります。
そんな中で、似ていて違ってうわってなるのが Kotlin の data class
で暗黙に生成される copy()
メソッドが Swift では生成されないことです。
ただ、コメントで指摘を受けて気付きましたが、Swift的には data class
的に struct
を使用する時は、プロパティは var で定義すれば、 let が伝播してくので不変になりますね。
そうなるとこの実装の役立つタイミングは、変更できない、例えばライブラリやモジュールの構造体を扱いたい時とかの限定的な場面だけになりそうです。
実装してみたところ、結構うまくいったので、共有します。
実装したいことは、「引数で指定したプロパティだけ変更して、他の項目は元と同じ別の struct を入手したい」です。
struct Bean {
let weight: Double
let size: Double?
let name: String?
}
extension Bean {
func copy(
weight: (() -> Double)? = nil,
size: (() -> Double?)? = nil,
name: (() -> String?)? = nil
) -> Bean {
Bean(
weight: choose(weight, value: self.weight),
size: choose(size, value: self.size),
name: choose(name, value: self.name)
)
}
}
func choose<T>(_ block: (() -> T)?, value: T) -> T {
guard let block = block else { return value }
return block()
}
copy()
メソッドの引数をOptionalのブロックにするのが思いつきです。
こちらの構造体は機械的で実装するのはまあまあ面倒ですが、使う時は例えば、
let blackSesame = Bean(weight: 0.1, size: 2.0, name: "黒ごま")
let whiteSesame = blackSesame.copy(name:{ "白ごま" })
こんな感じです。
extention はこんな実装もできそうです。どちらがいいかしら?
extension Bean {
func copy(
weight: (() -> Double)? = nil,
size: (() -> Double?)? = nil,
name: (() -> String?)? = nil
) -> Bean {
Bean(
weight: (weight ?? { self.weight })(),
size: (size ?? { self.size })(),
name: (name ?? { self.name })()
)
}
}
もっといい方法あったら、是非共有くださいませ。