5
Swiftでは、イニシャライザをプライベートにすることで、オブジェクトが直接初期化されるのを防ぐことができます。これをFactoryパターンで行うことができます。構造体上の拡張機能により、プライベート初期化の保護が不可能になる
ただし、拡張子を作成すると、別の初期化子を提供してコンパイルできます。拡張子が同じファイル内にあるかどうかは関係ありません。たとえば、ファクトリメソッドがいくつかのデータ検証を行う場合、これは重大な結果を招く可能性があります。
プライベートinitsについて何か不明ですか?これは非常に悪いようです。これを防ぐことはできますか?上記あたりzneakのコメントとして
struct Foo {
let data: Int
// factory method
static func makeFoo(data: Int) -> Foo {
return Foo(data: data)
}
// private init with data validation
private init(data: Int) {
guard data < 100 else {
fatalError("Foo should only have values under 100")
}
self.data = data
}
}
extension Foo {
init(someData: Int) {
// This bypasses the data validation and puts Foo into an invalid state.
self.data = someData
}
}
うーんで禁止されます。私はこれがバグだと言いたい。 'Foo'をクラスにするか、プライベートフィールドを追加するかのいずれかで回避することができます。 – Kevin
はいプライベートバッキングフィールドは動作しますが、それが異なるファイルにある場合のみです。間違いなくそこにバグ。 – MH175
問題の半分は既知の回復力のバグです。 AppleのJordan Roseは、[モジュール間の構造体初期化子が別のモジュール内構造体初期化子を呼び出すように強制する]提案をしています(https://github.com/jrose-apple/swift-evolution/blob/restrict-cross-module-struct- initializers/proposals/nnnn-restrict-cross-module-struct-initializers.md)。もちろん初期化子がプライベートであれば不可能です。 – zneak