Swift/パターン/タプル †タプル(tuple)とは複数個のデータを組にしたもの。 構造体とは異なり、メソッドやプロパティを付け加えることはできない。 値型のデータであり、代入によって新しいインスタンスが生成される。 let a:(String, Int) = ("monkey.jpg", 161_022") let b = ("monkey.jpg", 161_022) // 型推論を利用した let c = ("cat.jpg", 1024, 768) // 要素数は2個に限らない var d:(String, Int, Int) = c // 型が同じなので代入できる。タプルの代入はコピー。 d = a; // 型が異なるのでエラー。 タプルの各要素には ".0", ".1" のように、"."(ドット)の後に10進整数を指定してアクセスする。 この数字の部分を変数にすることはできない。 print("\(d.0): \(d.1) x \(d.2)") // cat.jpg: 1024 x 768 と表示される。 d.2 = 800 // dは変数(var)なので代入できる。 print("\(d.0): \(d.1) x \(d.2)") // cat.jpg: 1024 x 800 と表示される。 タプルは、相互に等しいかどうか調べる方法が提供されていない。次の例でもエラーとなる。 (1,2) == (1,2) タプルは異なる型の複数の要素を含むことができるので、比較することは単純ではないためだが、 ただし、「整数2つを含むタプル」などのように限定すれば演算子を定義することは可能である。 タプルと代入操作 †タプルは同じ型を持つ変数に代入が可能であり、一度の代入で各要素を別々の変数や定数に格納できる。 let photo = ("tiger.jpg", 640, 800) let (file,width,height) = photo // 定数file, width, heightを定義し、即、代入する。 print("\(file): \(width) x \(height)") // tiger.jpg 640 x 800 と表示される。 let (f,_,h) = photo // .0, .2 の値だけ取り出し、残り(.1)は捨てる タプルには任意のインスタンスを含めることができるので、タプルを含めることも可能。 let pic = ("snake.jpg", (640,480)) // タプルを含むタプル let (file,(w,h)) = pic // 要素を一度に取り出す let (name,_) = pic // 一部の値だけを取り出す タプルを使うと複数の要素を同時に代入できる。 var x = 1, y = 2 (x,y) = (y,x) print("x=\(x), y=\(y)") // x=2, y=1 と表示される タプルを返す関数 †関数から複数の値を返したいときにタプルを使うとよい。 func BMI(tall:Double, _ weight:Double) -> (Double,Double) { let ideal = 22.0 let t2 = tall * tall / 10000.0 // cmをmに換算する let index = weight / t return (index,ideal * t2) } let result = BMI(177.0, 80.0) print(result) // (25.5354, 68.9238) と表示される 値が1個だけのタプルは、その値自体と同じと見なされる。 関数の返り値がないことを、要素が1個もないタプル()で表現する。 Voidは()の別名である。 キーワード付きのタプル †関数の引数にキーワードをつけることができるように、タプルにもそれぞれの要素にキーワードをつけることができる。 let photo = (file:"tiger.jpg",width:640,height:800) "." (ドット)の後ろにキーワードをつけて要素にアクセスできる。 print(photo.0) // tiger.jpg と表示される print(photo.file) // tiger.jpg と表示される キーワードは全ての要素につける必要はなく、一部の要素にだけにつけても構わない。 同じキーワードがあっても構わないが、その要素にアクセスするには注意が必要になる。 let memo = (subject:"会合", 2016, 5, 16) let addr = (name:"名無しさん", mail:"nobody@xxx",mail:"nobody@yyy") キーワード付きのタプルと代入 †キーワードの付いたタプルは、同じキーワードのついたタプルは、キーワードのないタプルとの間でしか代入ができない。 let img = ("phoenix.jpg", 1200, 800) var v1: (String,Int,Int) = img var v2: (file:Strign,width:Int, height:Int) = img var v3: (image:Strign,x:Int, y:Int) = img let photo = (file:"tiger.jpg",width:640,height:400) v1 = photo v2 = photo v3 = photo // エラー。キーワードが異なる。 v3 = photo as (String,Int,Int) // 一旦キーワード無しのタプルにcastすれば代入できる。 キーワードがついたタプルは、要素の順番が違っていても同じキーワード同士で代入できる。 var x = 0, y = 0, z = 0 (red:x, green:y, blue: z) = (blue:5, red:250, green:220) // x=250,y=220,z=5になる var t: (red:Int, green:Int, blue:Int) = (blue:80, 0, 200) // t=(red:0,green:200,blue:80)になる タプルに型の別名をつけることができる。 typealias PhotoFile = (file:String,width:Int,height:Int) typealias ImageFile = (image:String,x:Int,y:Int) var w: PhotoFile = ("snake.jpg",width:768,height:1024) print(w.file) // snake.jpg と表示される キーワード付きのタプルを返す関数 †func BMI(tall:Double, _ weight:Double) -> (index:Double,ideal:Double) { let ideal = 22.0 let t2 = tall * tall / 10000.0 // cmをmに換算する let index = weight / t return (index,ideal * t2) } let a = BMI(177.0, 80.0) print("BMI=\(a.index), target=\(a.ideal)") // BMI=25.5354, target=68.9238 と表示される var b:(Double,Double) = BMI(177.0, 80.0) print("\(a.index)) // エラー。bはキーワードを持たないタプルだから。 タプルをswitch文で使う †case文のラベルにタプルを記述することが可能。ただし、記述されるタプルはすべて同じ型である必要がある。 switch day { // (Int,Int) 型の場合 case (1,1) : print("元旦") case (2,11) : print("建国記念日") case (5,3) : print("憲法記念日") default: break; } ある範囲の日付を表すために、範囲演算子を使って区間を記述することができる。 switch day { // (Int,Int) 型の場合 case (1,1...5) : print("正月休み") // 1/1 〜 1/5 case (2,11) : print("建国記念日") case (4,29), (5,2...6) : print("連休") // 4/29, 5/2-5/6 default: break; } 値を列挙するだけではなく、タプルの要素を取り出して処理に使うこともできる。 caseラベル無に let や var を記述して、case節の内部でのみ有効な変数や定数を宣言できる。 初期値は対応するタプルの要素の値となる。 switch day { // (Int,Int) 型の場合 case (1,1) : print("元旦") case (8,let d) : print("8/\(d) は夏休みです") case (12,_) : print("12月はずっと冬休みです") deefault: break; } switch文でwhere節を使う †switch文でタプルの要素に対して条件をつけることができる。 // dayOfWeek(1, d) は1月d日が月曜日の場合に1を返す関数であるとする switch day { case (1, let d) where d >= 8 && d <= 14 && dayOfWeek(1,d) == 1: print("成人の日") case (8,_): print("夏休み") case (let m, let d) where dayOfWeek(m,d) == 0: print("\(m)月\(d)日は日曜日") default: break } 上記のように要素毎にletを付けてもいいが、まとめて宣言することもできる。 case let (m,d) where dayOfWeek(m,d) == 0: print("\(m)月\(d)日は日曜日") どのラベルに一致したかによって値を持たない可能性があるので、 定数や変数を使うラベルは、別なラベルと","で区切って並べることができない。 また、同じ理由から上のラベルから fallthroughで遷移することができない。 switch day { case (1, let y), (2,2) : print("\(y)") // エラー。(2,2)のときyの値が不明。 case (2,_): fallthrough // エラー。zの値が不明になるので。 case (let z,2) : print("\(z)"); default: break; } オプショナル型をswitch文で使う †typealias People = (String,Int?) switch m { case let (name,age?) where age >= 18: print("\(name), 免許が取れる") case let (name,(15...18)?): print("\(name), 高校生") case let (let name,nil): print("\(name), 年齢不明") // 第2要素がnil case let (name, 15?) : print("\(name), 中学3年生") // (String, 15)にマッチする default: break } |