LoginSignup
66
64

More than 5 years have passed since last update.

Swiftに関するメモ その7 - 型変換

Last updated at Posted at 2014-06-17

https://developer.apple.com/swift/ より

The Swift Programming Language (iBooks Store)をざっくり目を通してつらつらと。

少しサボってしまいました。

配列・辞書における型の安全性 (Type safe)

Swift では、基本的に配列・辞書 (ディクショナリ) が、型安全 (type safe) で動作します。

例えば、以下のようなコード、

var array = ["1",2,3]

The Swift Programming Language (iBooks Store) の Collection Type の冒頭にある通り、配列の全て要素が一致しないため、エラーになります。実行前のコンパイル時点でエラーになるようです。


配列の全て要素が一致しないため、エラーになります。実行前のコンパイル時点でエラーになるようです。

と記載しましたが、型推論によってコンパイルエラーにはならないそうです。


同様に以下のコードもエラーになります。

class Fizz {
}
class Buzz {
}
class Foo {
}
class Bar {
}
var array = [Fizz(),Buzz(),Foo(),Bar(),Bar()]

Swift では標準的なベースクラスがないとされていています。

上記の例だとそれぞれのクラスが独立していて、上記のサンプルコードでは、型の一致性が保証できないためです。


@takabosoft さんがコメントでご指摘されたように import Cocoa を宣言したりすると、コンパイラが型推論できる範囲が広がり、上記コードでもエラーにならなくなる場合があるようです。

Swift の配列に関しての動作は、理解しづらい代入時の動作なども含めて、今後変わってくる可能性があると個人的には思っています。


以下ようなコードだと動作します。

class BaseClass {
}
class Fizz : BaseClass {
}
class Buzz : BaseClass {
}
class Foo : BaseClass {
}
class Bar : Foo {
}
var array = [Fizz(),Buzz(),Foo(),Bar(),Bar()]

配列の全て要素がベースクラス BaseClass のアップキャストできるので、型の一致性が保たれます。

AnyObjectAny

異なる型の値を配列・辞書に混在させたい場合には Any を利用することができます。

var array : Any[] = ["1",2,3]

この時、要素として指定できるのは関数以外の全ての型のようです。

AnyObject は若干適用範囲が狭く、クラスのインスタンスに対して利用できます。したがって、AnyObjectIntBool などのプリミティブな型は指定できません。

先ほどのサンプルコード、

class Fizz {
}
class Buzz {
}
class Foo {
}
class Bar {
}
var array = [Fizz(),Buzz(),Foo(),Bar(),Bar()]

はエラーになりましたが、AnyObject を明示すればエラーにはなりません。

class Fizz {
}
class Buzz {
}
class Foo {
}
class Bar {
}
var array : AnyObject[] = [Fizz(),Buzz(),Foo(),Bar(),Bar()]

型チェック is

is を使うと変数・定数に対しての型チェックを行うことができます。

class BaseClass {
}
class Fizz : BaseClass {
}
class Buzz : BaseClass {
}
class Foo : BaseClass {
}
class Bar : Foo {
}
var array = [Fizz(),Buzz(),Foo(),Bar(),Bar()]
for obj in array {
  if obj is Bar {
    println("obj is Bar")
  }
}

isInt などのプリミティブな型に対しても動作します。Objective-C の isKindOfClass: とはこの点で異なります。

var array : Any[] = ["1",2,3]
for obj in array {
  if obj is Int {
    println("\(obj) is Int") // 2 is Int & 3 is Int
  }
}

型変換 asas?

共通するベースクラスにアップキャストされたインスタンスを、ダウンキャストするには as が利用できます。この時、? を付けたオプショナル形式を利用することができます。

let bar = obj as Bar // 定数 bar に対して obj から Bar でダウンキャストしたインスタンスを代入する

? をつけない場合は強制的な型変換になります。この時、変換の対象となる変数・定数がその型に変換できない場合、エラーになります。

それに対して ? をつけると、変換後の定数・変数に任意型 (optinal) を取るような動作になり、変換対象がその型に変換できない場合には nil が入ります。

それを利用すると、

for obj in array {
  if obj is Bar {
    let bar = obj as Bar
    // bar について何かする
  }
}

というコードを

for obj in array {
  if let bar = obj as? Bar {
    // bar について何かする
  }
}

のように記述できます。

switch 構文での asis

switch 文の caseisas を使って条件分岐を実現できます。

switch obj {
  case is Bar: // obj が Bar だったら => if obj is Bar と同じ
    // .... 省略
  case 0 as Int: // obj が整数の 0 の場合 => if obj as? Int == 0 と同じような意味
    // .... 省略
  case 0 as Double: // obj が Double の 0.0 の場合 => if obj as? Double == 0.0 と同じような意味
    // .... 省略
}

caselet などを使って定数に代入もできます。

switch obj {
  case let bar as Bar: // if let bar = obj as? Bar と同じ
    // .... この中で bar がローカルな定数として利用できる
}

if 文で as? を使うような場面でも switch 文の case では as を利用しています。

switch 内のコンテクストで case での強制的な型変換はエラーにならないようです (そもそもマッチしない)。

参考 → as と is の入った switch 文を if 文で記述してみる

66
64
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
66
64