web-dev-qa-db-ja.com

オプションではないAnyがnilを保持できるのはなぜですか?

In Swift Any型の定数を宣言し、それにStringを入れることができます。

let any: Any = "hello world"

良い。一方、I cannotはオプションではないため、nil値をanyに入れます。

let any: Any = nil

error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
let any: Any = nil
              ^

パーフェクト。しかし、コンパイラはなぜ次のコードを書くことを許可するのですか?

let couldBeNil: String? = nil
let any: Any = couldBeNil
print(any) // nil

Anyは、Swiftオプションのvar/letにのみnilを入力できるという規則に従っていませんか?

Xcode Playground 7.2でテスト済み+ Swift 2.1.1

33
Luca Angeletti

TL; DR; Swiftのオプションは、コンパイラによってOptional enumインスタンスに変換され、Anyは任意の値、オプションの保存に使用できます。


Swiftはオプションを表しますか?)SomeType?Optional列挙型の具体的な実装にマッピングすることで行います。

Int? => Optional<Int>
String? => Optional<String>

Optionalの簡易宣言は次のようになります。

enum Optional<T> {
    case none    // nil
    case some(T) // non-nil
}

これで、タイプAnyの変数は列挙値(またはその他の種類の値、またはメタタイプ情報)を保持できるため、たとえばnil文字列を保持できるはずです。 、別名String?.none、別名Optional<String>.none

しかし、何が起こるか見てみましょう。 Optional宣言でわかるように、nilはすべてのタイプの.none enumケースに対応します。

nil == Optional<String>.none // true
nil == Optional<Int>.none    // true
[Double]?.none == nil        // also true

したがって、理論的には、nilとして宣言された変数にAnyを割り当てることができるはずです。それでも、コンパイラはこれを許可しません。

しかし、コンパイラがnilAny変数に割り当てることができないのはなぜですか? .none enumケースをマッピングするタイプを推測できないためです。 Optionalはジェネリック列挙型であるため、Tジェネリックパラメーターを埋める何かが必要であり、プレーンnilは広すぎます。どの.none値を使用する必要がありますか? Intからのもの、Stringからのもの、別のもの?

これにより、上記の段落をサポートするエラーメッセージが表示されます。

let nilAny: Any = nil // error: nil cannot initialize specified type 'Any' (aka 'protocol<>')

次のコードは機能し、nilを割り当てるのと同じです。

let nilAny: Any = Optional<Int>.none

、上記のAny変数は実際にOptional enumの有効な値を保持しているためです。

nilOptional<Type>.noneに変換されるため、間接的な割り当ても機能します。

var nilableBool: Bool? // nilableBool has the Optional<Bool>.none value
var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool

他の言語とは異なり、Swift nilは具体的な値に対応します。ただし、コンパイラがどのOptional<T>.noneを割り当てる必要があるかを知るには、動作する型が必要です。キーワードは、砂糖の構文を提供するものと考えることができます。

62
Cristik

Swift Docs: "Any:すべてのタイプが暗黙的に準拠するプロトコル。"

すなわちtypealias Any = protocol<>

したがって、String?、あなたはそれをOptional<String>、 どこ Optional<T>は次のように実装できます。

enum Optional<T> {
  case Some(T), None
}

また、列挙型はタイプであるため、Anyプロトコルに準拠しています。コメントに記載されているように、nilは型ではありません(したがって、Anyに準拠していません。値がありません(この場合、値には型がありません)。

オプションは言語に組み込まれ、通常の列挙型ではありませんが、Anyに準拠しているが、型のないnilには準拠していないことは変わりません。

8
Alex Popov

Anynilが含まれているかどうかを確認する方法を探している人向け:

po valueを呼び出すと、Any変数に値nilが含まれていることが通知される場合、次の行はまだ機能しません。

if value == nil { ... } // Returns false and generates a warning

チェックする前に、まずAnyDateが含まれている可能性がある場合など、nillable値に変換する必要があります。

if Optional<Date>.none == value as? Date { ... } // Returns true and no warning

注:私はそれをテストしなかったので、保証はありませんが、次のように書かれた場合、上記の行も通過する可能性があります:

if Optional<Any>.none == value as? Any { ... }
2
Departamento B