String
とString!
同一ではありません。それらの間で変換するのに十分な砂糖が言語にたまたまあるだけです。String
同様に、言語には と の間で変換する砂糖がありますString?
(ただし、逆ではありません)。
基本から始めましょう。ありますString
。特別な理由がない限りString
、文字列を意味する場合に使用する必要があります。それ以外はすべて「より多くのもの」であり、必要でない限り追加しないでください。
ありますOptional<String>
。これは、値がある場合と値がない場合の 2 つのケースを持つ単なる列挙型です。
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
// ...
}
利用可能な場合は戻り、利用できない場合はクラッシュする後置演算子があり!
ます。これまでのところ、魔法はありません。これは自分で構築できるものです。Optional
Wrapped
周りには魔法のかけらがいくつかあるOptional
。まず、型はコンパイラによってWrapped?
魔法のように変換されます (任意の)。これは単なるシンタックス シュガーです。2 つの表記法は同じです。第二に、「演算子」とのオプションの連鎖があります(実際には演算子ではありません。言語の一部であり、自分で構築することはできません)。そして、オプションのプロモーションがあります。必要に応じて、任意の型を自動的かつ暗黙的に変換できます。構文のような魔法の部分は他にほとんどなく、 の同義語があります (実際には同じだと思います)。しかし、実際には列挙型として実装された単なるジェネリック型です。これ'Optional<Wrapped>
Wrapped
?.
Wrapped
Wrapped?
Optional
if-let
nil
Optional.None
Optional
次にありますImplicitlyUnwrappedOptional<Wrapped>
。これも単なる列挙型です (Swift 2.2 では、これは Swift 3 で変更されます)。
public enum ImplicitlyUnwrappedOptional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
// ...
}
これは と同じOptional
ではなく、 と同じでもありませんWrapped
。全く違うタイプです。しかし、それに関連するいくつかの魔法もあります。まず、型Wrapped!
は のシンタックス シュガーですImplicitlyUnwrappedOptional<Wrapped>
。繰り返しますが、それはただの砂糖です。この 2 つは同じです (Swift 3 ではなく Swift 2.2 で)。次に、期待されるIUO<Wrapped>
場所で が見つかった場合Wrapped
、自動的に変換されるWrapped
か、値がないとクラッシュします。予想される場所で見つかった場合、Wrapped?
自動的に に変換されWrapped?
ます。それらは魔法のようであり、それがと が同じタイプのように見えることがあるのはそのためString
ですString!
。それは、目に見えない変換ステップを追加することにより、コンパイラが魔法のように「機能させる」だけです。本当に同じタイプというわけではありません。
IUO は、特に Storyboard を含む特定の Objective-C パターンへの橋渡しに最も役立ち、そのような状況以外では避けるべきです。そのような状況でも、IUO は便利です。通常のオプションを使用してすべて同じことを行うことができますが、if-let
より頻繁にチェックする必要があるだけです。Optionals を使用すると、IUO を使用するよりもはるかに安全です。「この値は、使用される前に常に設定されることが確実にわかっている」と考えるのは簡単です。そしてちょうど今週、私はそれについて間違っていたためにクラッシャーを追跡しました. 「あるべき」と「あるべき」は違います。しかし、Storyboards の Optionals で完全に安全であることは非常に不便であり、(クラッシュするのではなく何もしないことで) いくつかのバグを隠す可能性があるため、IUO の最も一般的な場所です。
IUO プロパティは、失敗する可能性のあるinit
メソッドを処理するために重要でした。これは Swift 2.2 ではもはや問題ではないため、その使用はなくなりました。私が遭遇する最後の「純粋な Swift」の使用は、プロパティとして保存するものの初期化子に渡す必要がある場合です(すべてのプロパティが初期化されているため、その時点でself
渡すことはできません)。self
これは残念なユースケースであり、非常に厄介です。修正を考え出すことを願っています。このようなケース以外では、暗黙的にラップ解除されたオプションを避ける必要があります。