2

String!タイプとタイプの違いがよくわかりましたString?。しかし、Stringタイプはどうですか?String!String?迅速な違いは何ですか?String!タイプはタイプと同じStringですか?

たとえば、次のようなクラスがあります。

class Person {
  private var _name: String!

  var name: String {
      return _name
  }

  init(name: String) {
     _name = name
  }
}

Stringコンパイラ エラーはありません。型が型と同じであるように見えますString!。しかし、よくわかりません...

4

5 に答える 5

4

StringString!同一ではありません。それらの間で変換するのに十分な砂糖が言語にたまたまあるだけです。String同様に、言語には と の間で変換する砂糖がありますString?(ただし、逆ではありません)。

基本から始めましょう。ありますString。特別な理由がない限りString、文字列を意味する場合に使用する必要があります。それ以外はすべて「より多くのもの」であり、必要でない限り追加しないでください。

ありますOptional<String>。これは、値がある場合と値がない場合の 2 つのケースを持つ単なる列挙型です。

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
    case None
    case Some(Wrapped)
    // ...
}

利用可能な場合は戻り、利用できない場合はクラッシュする後置演算子があり!ます。これまでのところ、魔法はありません。これは自分で構築できるものです。OptionalWrapped

周りには魔法のかけらがいくつかあるOptional。まず、型はコンパイラによってWrapped?魔法のように変換されます (任意の)。これは単なるシンタックス シュガーです。2 つの表記法は同じです。第二に、「演算子」とのオプションの連鎖があります(実際には演算子ではありません。言語の一部であり、自分で構築することはできません)。そして、オプションのプロモーションがあります。必要に応じて、任意の型を自動的かつ暗黙的に変換できます。構文のような魔法の部分は他にほとんどなく、 の同義語があります (実際には同じだと思います)。しかし、実際には列挙型として実装された単なるジェネリック型です。これ'Optional<Wrapped>Wrapped?.WrappedWrapped?Optionalif-letnilOptional.NoneOptional

次にあります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これは残念なユースケースであり、非常に厄介です。修正を考え出すことを願っています。このようなケース以外では、暗黙的にラップ解除されたオプションを避ける必要があります。

于 2016-04-04T00:02:22.937 に答える
1

これら 2 つの関数の違いに注意してください。

func f() {
    let x: String? = nil
    guard let y: String = x else {
        print("failed")
        return
    }
}

func g() {
    let x: String? = nil
    guard let y: String! = x else {
        print("failed")
        return
    }
    print(y.dynamicType, y)
}

f() # failed
g() # Optional<String> nil
于 2016-04-04T00:02:27.577 に答える
1

String同じでString!あると同時に異なっています。let または var を として宣言する場合、メソッドStringに何らかの値を設定する必要がありますinit。必要に応じて値を設定できるように宣言すると、String!この値を読み取る前にそれを行う必要があります。

したがって、あなた_nameが になるとnil、アプリはクラッシュします。

として宣言すると、コンパイラは最初の読み取りの前にそれStringを保証します。_name != nilと宣言する場合はString!、それを保証する必要があります。

このため、これらのものは同じタイプです。

var test1: String = "test"
var test2: String! = "test"

if test1 is String { // True
    print("test1 is String")
}
if test2 is String { // True
    print("test2 is String")
}

このタイプは同じですが、これは異なります

于 2016-04-03T20:17:44.680 に答える
0

ここでの回答よりも、迅速なドキュメントを読むことをお勧めします。Swift の型システムを正しく理解することは非常に重要なので、まずそれを行います。

于 2016-04-03T22:11:42.827 に答える