swift の as as! as? オペレータ (Type Cast Operator) と is (Type Check Operator) とパターンマッチ
環境
as オペレータ
class Animal {} class Dog: Animal {} let dog = Dog() let animal = dog as Animal // アップキャスト let floatValue = 1 as Float // 型指定
as! オペレータ
- 強制的にダウンキャスト
- ダウンキャストが成功することが分かっている場合に使用
- ダウンキャストが失敗するとruntimeエラーになる
let animal1: Animal = Dog() let dog = animal1 as! Dog // OK let animal2 = Animal() let dog2 = animal as! Dog // ダウンキャストできないのでruntimeエラー
as? オペレータ
- ダウンキャストが成功するか分からない場合に使用
- 戻り値はオプショナル型
- 失敗した場合はOptional
.None
let animal1: Animal = Dog() let dog = animal1 as? Dog // dogの型はOptional<Dog> let animal2 = Animal() let dog2 = animal as? Dog // エラーは起こらない。dog2の中身は.None if let dog = dog2 { print("dog is not nil") } else { print("dog is nil") } // 出力: dog is nil
is 型チェックオペレータ
- isオペレータはインスタンスがある型のサブクラスの型か判定するときに使用
- 戻り値はある型のサブクラスの型のとき true, そうでないとき false
let animal = Animal() let isDog = animal is Dog print(isDog) // 出力: false let dog = Dog() let isAnimal = dog is Animal print(isAnimal) // 出力: true // AnyObject型にしないとコンパイラがSmartすぎて // 下の警告がでるためAnyObjectにしている: // 'is' test is always true let isDog2: AnyObject = dog is Dog print(isDog2) // 出力: true
as と is パターンマッチ (Type-Casting Patterns)
ややこしことに is, as はswitchのパターンマッチと一緒に使用できる。
class Animal { func bark() -> String { return "$&%#" } } class Dog: Animal { override func bark() -> String { return "woof-woof" } } let things: [Any] = [0, 0.0, Animal(), Dog()] for thing in things { switch thing { // thingがIntか判定。値自体に興味はないときに is を使用する case is Int: print("thing is Int value") case is Float: print("thing is Float") // thingがDogにマッチするか判定し // (asの右側のタイプかそのサブタイプか)、 // マッチした場合、Dogにキャストされたdogを取得 case let dog as Dog: print("Dog barks " + dog.bark()) case let animal as Animal: print("Animal barks " + animal.bark()) default: print("something else") } } /* 出力: thing is Int value thing is Float Animal barks $&%# Dog barks woof-woof */