#author("2016-05-14T09:28:38+00:00","default:nitta","nitta")
[[Swift/pattern]]

このページは以下の本を参考にしています。
 詳細Swift改訂版
 著者: 荻原剛志
 出版社: SBクリエイティブ株式会社 (2016/01/01)
 ISBN: 978-4-7973-8625-7
http://isbn.sbcr.jp/86257/

*Swift/パターン/タプル [#r1cd5edb]

タプル(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つを含むタプル」などのように限定すれば演算子を定義することは可能である。


**タプルと代入操作 [#k329e65d]
タプルは同じ型を持つ変数に代入が可能であり、一度の代入で各要素を別々の変数や定数に格納できる。
 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 と表示される

**タプルを返す関数 [#ybfb3acb]
関数から複数の値を返したいときにタプルを使うとよい。
 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は()の別名である。

**キーワード付きのタプル [#u7563dce]
関数の引数にキーワードをつけることができるように、タプルにもそれぞれの要素にキーワードをつけることができる。
 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")

**キーワード付きのタプルと代入 [#c55fb1d1]
キーワードの付いたタプルは、同じキーワードのついたタプルは、キーワードのないタプルとの間でしか代入ができない。
 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 と表示される

**キーワード付きのタプルを返す関数 [#t0c73178]

 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文で使う [#g8c32554]

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節を使う [#u97f668e]
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文で使う [#k5895ec3]
 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
 }



トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS