Swift をいろいろいじっていたところ、辞書に挿入するオブジェクトをダウンキャストすると、奇妙な警告が表示されることに気付きました: 。を にTreating a forced downcast to 'String' as optional will never produce 'nil'
置き換えると、警告は消えます。as
as?
func test() -> AnyObject! {
return "Hi!"
}
var dict = Dictionary<String,String>()
dict["test"]=test() as String
Appleのドキュメントには次のように書かれている
ダウンキャストは失敗する可能性があるため、型キャスト演算子には 2 つの異なる形式があります。オプション形式 は、
as?
ダウンキャストしようとしている型のオプション値を返します。強制形式 は、as
ダウンキャストを試行し、結果を単一の複合アクションとして強制的にアンラップします。
as?
ここでの代わりにを使用するのがなぜas
正しいのかはわかりません。いくつかのテストにより、test() を変更して String ではなく Int を返すようにした場合、 を使用し続けるとコードがエラーで終了することがわかりましたas
。 を使用するように切り替えた場合as?
、コードは通常どおり実行を続行し、そのステートメントをスキップします (dict は空のままになります)。ただし、なぜこれが望ましいのかはわかりません。私としては、エラーでプログラムが終了し、キャストが失敗したことを知らせる方が、誤ったステートメントを単に無視して実行を続けるよりも望ましいと思います。
ドキュメントによると、強制形式は「ダウンキャストが常に成功することが確実な場合のみ」使用すべきとのことです。この場合、test()
文字列しか返せないことがわかっているので、ダウンキャストが常に成功することは確実です。したがって、これはダウンキャストの強制形式に最適な状況だと想定します。では、なぜコンパイラが警告を出すのでしょうか?
ベストアンサー1
最後の行を詳しく見て、何が起こっているのかを見てみましょう。
let temporaryAnyObject = test()
let temporaryString = temporaryAnyObject as String
dict["test"] = temporaryString
エラーは 2 行目にあります。ここでは、 がtemporaryAnyObject
確実に であることをコンパイラに強制するように指示しています。コードはコンパイルされますが (警告をエラーとして扱わないと仮定)、 が実際には でないString
場合はクラッシュします。temporaryAnyObject
String
as
なしで が機能する方法?
は、基本的に「今後、結果が実際にその型である場合は、この式の結果をその型として扱います。そうでない場合は、一貫性がなくなり、実行できなくなります。」と言っています。
の方法as?
は ( を使用?
)、「今後、結果が実際にその型である場合は、この式の結果をその型として扱い、そうでない場合は、この式の結果は になります」と言っていますnil
。
したがって、上記の展開された例では、test()
が を返す場合String
、as
ダウンキャストは成功し、temporaryString
になりますString
。test()
が を返さずString
、 またはInt
String からサブクラス化されていない他の何かを返した場合、 はas
失敗し、コードは実行を継続できなくなります。
これは、完全な制御権を持つ開発者として、オプション インジケーターを配置しないことで、システムにこのように動作するように指示したためです?
。このas
コマンドは、オプションの動作を許容せず、ダウンキャストが機能する必要があることを具体的に意味します。
を入れた場合?
、temporaryString
となりnil
、3 行目では辞書から「test」キー/値ペアが単純に削除されます。
これは奇妙に思えるかもしれませんが、これは、すべてをデフォルトでオプションとして扱い、独自のチェックとアサートを配置することに依存する Obj-C などの多くの言語のデフォルトの動作とは逆であるためです。
編集 - Swift 2 アップデート
Swift 2 以降では、強制された失敗可能なダウンキャスト演算子as
は削除され、as!
より Swift らしい に置き換えられました。動作は同じです。