ユーザ定義型[構造体・列挙型]
ポイント
1 構造体・列挙型という2つのユーザ定義型
2 列挙型とswitch-caseは組み合わせて使うとバグの発生を防ぐ強力な仕様
3 構造体・列挙型ではストアドプロパティにタイププロパティが使える
構造体
- 構造体の定義
struct Point { var x = 0, y = 0 } struct Size { var width = 0, height = 0 func area() -> Int { return width * height } } // 構造体を利用したインスタンスの作成 struct Rectangle { var origin = Point() var size = Size() }
- 構造体特有のイニシャライザ
var origin = Point(x: 0, y: 0) var size = Size(width: 0, height: 0) // パラメタは定義順で指定
列挙型
一連の値とそれを表す値をまとめたもの
- 列挙型の定義
// トランプのスート(記号)を表す列挙型 enum Suit { // メンバ case Spades, Hearts, Diamonds, Clubs // メソッド定義 func color() -> String { switch self { // 自身のメンバを参照 case .Spades, .Clubs: return "black" case .Hearts, .Diamonds: return "red" } } } var s = Suit.Spades s = .Hearts // 列挙型の省略記載 s.color() // red
列挙型に固有数値はもっていないが以下のように指定可能 - 特定の値を持つ列挙型
enum Suit: Int { // 列挙型に型を持たせる case Spades = 0 case Hearts = 1 case Diamonds = 2 case Clubs = 3 } var s = Suit.Spades s.toRaw() // 0 // toRaw()でアクセス // オプショナルバインディグを使用して・・・ if let unwraped = Suit.fromRaw(3) { // fromRaw()メソッドを利用して値からインスタンスを作成している unwraped.toRaw() // 3 }
列挙型に指定した型が数値型(整数・浮動小数)の場合、値の指定を省略可
- 値の省略
enum Suit: Int { case Spades, Hearts, Diamonds, Clubs }
値の指定は最初だけすると、後は自動的に定義順に順番に連番がふられる
- 値の一部省略
enum DayOfTheWeek: Int { case Sunday = 1 case Monday, Tuesday, Wednesday, Thursday, Friday, Saturday } var d = DayOfTheWeek.Monday
- アソシエイト値
メンバの値に別の値を関連付ける。メンバごとに異なる型を持つといこと。
そのような値を「アソシエイト値」という。
enum ItemCode { case JAN(String) case ISBN(String) case ItemId(Int) }
- アソシエイト値の使用
var itemCode = ItemCode.ISBN("4798039519") switch itemCode { case .JAN(let janCode): println("JANコード: \(janCode)") case .ISBN(let isbnCode): println("ISBNコード: \(isbnCode)") case .ItemId(let itemId): println("商品ID: \(itemId)") }
構造体や列挙型の特徴
- ストアドタイププロパティ
struct Point { static var offsetX = 0, offsetY = 0 // var letではなくstaticでタイププロパティ定義 var x = 0, y = 0 // コンピューテッドプロパティ var actualX: Int { return x + Point.offsetX } var actualY: Int { return y + Point.offsetY } } Point.offsetX = 100 Point.offsetY = -100 var p Point(x: 150, y: 150) p.actualX // 250 p.actualY // 50
- 参照型の変数代入
class RefType { var a = 0 } var ref1 = RefType() //インスタンス作成 var ref2 = ref1 ref2.a = 100 ref2.a // 100 ref1.a // 100
構造体と列挙型は値型
インスタンスコピーは内容コピー
- 値型の変数代入
struct ValueType { var a = 0 } var value1 = ValueType() var value2 = value1 // コピーの代入 value2.a = 100 value2.a // 100 value1.a // 0
- 定義インスタンスの更新
・構造体や列挙型の新スタンスが定数に格納されている場合は変更不可 プロパティを変更可能なクラスとは違う
- タイプメソッド
// 構造体・列挙型はstaticキーワード struct ProgressBar { static var progress = 0 static func gain() { ProgressBar.progress++; } } ProgressBar.progress // 0 ProgressBar.gain() ProgressBar.gain() ProgressBar.progress // 2
- メソッド内でのプロパティ更新
struct Point { var x = 0, y = 0 } struct Size { var width = 0, height = 0 func area() -> Int { return width * height } } struct Rectangle { var origin = Point() var size = Size() mutating func moveByX(x: Int, y: Int) { origin.x += x origin.y += y } } var r = Rectangle() r.moveByX(50, y:50) r.origin // {x 50, y 50}
- selfキーワードを仕様した自分自身の更新
struct Point { var x = 0, y = 0 mutating func reset() { self = Point() } } var p = Point(x: 100, y: 100) p // {x 100, y 100} p.reset() p // {x 0, y 0}