Swift/基本的なデータ型 †整数と実数 †
数値型のリテラル
Swiftには暗黙の型変換はあにので、イニシャライザをつかって明示的に型変換を行う。 範囲型と区間型 †
3つとも整数をパラメータに指定できる。 半開区間型や、閉区間型は実数や文字、捩れつもパラメータに指定できる。 var inth : HalfOpenInterval<Int> = 0..<10 // 10は含まない var intc : CloseInterval<Int> = 0...10 // 10は含む var rg : Range<Int> = 0..<10 // 範囲型では0..<10でも0...9でも同じ var inth = HalfOpenInterval<Int>(0,10) // 10は含まない var intc = CloseInterval<Int>(0,10) // 10は含む var rg = Range<Int>(start: 0, end: 10) // 10は含まない あるインスタンスが区間や範囲に含まれるかどうかという条件は、switch 文の case に指定できる。また、~= という演算子でも調べることができる。 var sintv = "archer" ... "saber" // 文字列型の区間 if sintv ~= "lancer" { print("yes") } // trueなので "yes"が表示される var rg: Range<Int> = -5 ... 5 // 整数型の範囲 if rg ~= 9 { print("yes") } // falseなので"yes"は表示されない
配列 †Objective-C では NSArray型と NSMutableArray型が存在し、データを変更できる配列か どうかを区別していた。 Swiftではデータ型でデータの可変性を区別するのではなく、 配列が変数に代入されているか(要素を変更できる)、 定数に代入されているか(変更できない)で区別する。 配列は値型のデータ型である。 配列のインスタンスを変数に代入したり、関数に対して引数として渡したりする際に 必要に応じて新しいインスタンスが生成される。 すなわち、元の配列の内容に影響はない。 配列の比較には == や != 演算子を使う。 配列の要素数が等しく、先頭から順番に対応する要素がそれぞれ等しい場合に == はtrueを返す。 let a = [1, 2] let b = [2, 1] a == b // false a + [1] == [1] + b // true: どちらも [1, 2, 1] となるため 配列の添字に整数型の範囲を指定することによって、その添字の範囲からなる新しい配列を作ることができる。 var dogs = ["a", "b", "c", "d", "e", "f" ] let sub = dogs[1..4] print(sub) // [ "b", "c" "d" ] を表示する 配列の添字として範囲を指定して、別の配列を代入するとその部分を新しい内容で置き換えることができる。 置き換え前と後の要素数は一致していなくてもよい。 var s = [ "a", "b", "c", "d" ] s[0...0] = [ "1", "2", "3" ] // s[0]では駄目 print(s) // ["1", "2", "3", "b", "c", "d"] と表示される s[1...3] = [ "x", "y", "z" ] print(s) // ["1", "x", "y", "z", "c", "d" ] と表示される s[3...4] = [] // 削除にも利用できる print(s) // ["1", "x", "y", "d" ] と表示される 配列の添字に範囲を指定すると部分配列が得られる(ただし型は Array型 ではなく ArraySlice型)。 ArraySlice型では、添字は0から始まるとは限らず、指定した範囲だけが利用できる。 var days = [ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" ] let sub = days[2..<5] // ArraySlice型 print(sub) // ["Wed", "Thu", "Fri"] と表示される print(sub.count) // 3 と表示される print(sub.startIndex) // 2 と表示される。ArraySliceの最初の添字なので。 print(sub[2]) // "Wed" と表示される print(sub[4]) // "Fri" と表示される let subarray = [String](sub) // subarrayはArray型 print(subarra[0]) // "Wed" と表示される ArraySlice型は、元の配列の一部を参照するために作られたデータ。 それぞれは別の配列なので、どちらかの内容を変更してももう一方に影響はない。 配列とプロトコル
配列のイニシャライザ var a : Array<Int> = [ 2, 5, 8, 11, 7 ] var s = Array<String>() 配列を生成する際に利用できるイニシャライザは次の通り。
配列のプロパティ
配列のメソッド
可変個の引数が利用できる関数 func maxOfInts(first: Int, _ params: Int...) -> Int { var m = first for v in params { if m < v { m = v } } return m } print( maxOfInts(3,9,2,6) ) // 9 print( maxOfInts(108, 88) ) // 108 print( maxOfInts(107) ) // 107。可変個の部分が0個でもよい。 関数の意味から、引数は必ず一つは必要なので firstという引数と可変個の部分を担当するparams という引数を用意している。型名の後に "..." と記述すると、その直前の 仮引数には、実際に指定された引数が格納された配列が渡される。 Swiftでは、引数が可変個の部分は引数列の最後に限定されているわけではない。 可変個の引数の次に外部引数名を持つ引数を置けば、引数列の途中を可変個にすることができる。 func cards(numbers: Int..., label:String) { for n in numbers { print(label + String(n), terminator:" ") } print("") } cards(3, 5, 7, 8, label:"例") // "例3 例5 例7 例8"を表示する 多次元配列 var table: [[String]] = [["A", "B"], ["X", "Y", "Z"]] print(table[0]) // ["A", "B"] と表示される print(table[1][0]) // "X" と表示される table[0].removeAtIndex(1) // "B" が削除される print(table) // [["A"], ["X", "Y", "Z"]] と表示される オプショナル型による配列の空要素 var sparse:[Int?] = [ 1, 2, nil, 4, nil ] var space = [Int?](count:10, repeatedValue: nil) // nilが10個入った配列 文字列と文字 †String型のイニシャライザ
String型のプロパティ
String型の演算子 (Comparableプロトコルに適合している)
Character型にはUnicode(またはASCII code)の文字を1文字格納できる。 Character型同士は連結できない。文字列の末尾に連結するには appendメソッドを使う。 let atmark: Character = "@" // ASCII code "@" let ditto: Character = "\u{3005}" // Unicode "々" let chain= Character("鎖") // イニシャライザを使う UnicodeScalar型は、Unicodeに対応した文字を保持でき、21bitまで表すことができる。 イニシャライザに Int型 (または Int32型) を指定する。 let us1 = UnicodeScalar(0x83ef) // "華" let us2 = UnicodeScalar("華") let us3 : UnicodeScalar = "華" UnicodeScalar型は相互に大小比較が可能であり、Unicode文字コードをInt型で返すvalueというプロパティがある。 us1 > us2 // true or false let u = us3.value // uはUInt32型で、値は 0x83ef UnicodeScalar型を使うと、Character型よりも文字コードが特定の範囲内にあるかどうかを判断しやすい。 平仮名だけを取り出す例 let text = "Swiftで、iPhoneアプリ作れます。" let first = UnicodeScalar(0x3041) // "ぁ" 平仮名の先頭 (HIRAGANA LETTER SMALL A) let last = UnicodeScalar(0x309f) // "ゟ" 平仮名の最後 (HIRAGANA DIGRAPH YORI) var kana = "" for sc in text.unicodeScalars { // UnicodeScalar型を得る if sc >= first && sc <= last { // 平仮名ならば kana.append(sc) } } print(kana) 合成された文字とCharacter型 †Unicodeの文字を複数個合成して「書記素クラスタ (grapheme cluster)」がある。 ドイツ語における「ウムラウト a」は、U+00E4 という1文字で表す方法と、 a という文字(U+0061)と、「ウムラウト」という文字(U+0308)という2文字を組合せて表す方法がある。 同様に日本語の「グ」も、1文字で(U+30B0)と表す方法と、「ク」(U+_30AF)と「濁点」(U+3099)の組合せで表す方法がある。 let gu : Character = "\u{30B0}" // グ let ku : Character = "\u{30AF}\u{3099}" // ク+濁点 print(gu == ku) // true と表示される Character型は1つ以上の文字コードを組合せた書記素クラスタを格納できるデータ型である。 文字列の長さと文字データの取り出し方 †func show(str: String) { print("Ch:\(str.characters.count), " + "US:\(str.unicodeScalars.count)," + "U16:\(str.utf16.count)") var a = "/" for cc in str.characters { a+= "\(cc)/" } print(a) var b = "/" for cc in str.unicodeScalars { b+= "\(cc)/" } print(b) } Character型で取り出すと、合成された文字(書記素クラスタ)をひとまとまりにして取り出すことがわかる。 let s1 = "\u{30AE}モー\u{30F4}" // "ギモーヴ" show(s1) Ch:4, US:4, U16:4 /ギ/モ/ー/ヴ/ /ギ/モ/ー/ヴ/ UnicodeScalars型だと、Unicodeのデータを1つずつ取り出す場合に使うことができる。 let s2 = "\u{30AD}\u{3099}モー\u{30A6}\u{3099}" // "{キ+濁点}モー{ウ+濁点}" show(s2) Ch:4, US:6, U16:6 /ギ/モ/ー/ヴ/ /キ/゛/モ/ー/ウ/゛/ 指定一の文字および部分文字列の取り出し方 †
String.Index型は bidirectionalIndexTypeプロトコルに適合しているので、次のメソッドを持つ。
let s = ”俺、Swiftプロク\u{3099}ラマになります。” print( s[str.startIndex] ) // "俺" print( s[str.startIndex.successor()] ) // "、" print( s[advance(str.startIndex,9)] ) // "グ" print( s[str.endIndex.predecessor()] ) // "。" print( s[advance(str.endIndex,-3)] ) // "ま" let x = advance(str.startIndex, 7) let y = advance(x, 5) print( s[x ..< y] ) // "プログラマ" String型のメソッド †
SwiftのString型は、Objective-CのNSString型と相互に互換性がある。 Foundationをimportすると、NSStringに提供されているメソッドがString型で利用できるようになる。 辞書 †key(キー)とvalue(値)の組を複数格納できる、コレクションの一種。 キーの型と値の型はそれぞれで統一されている必要がある。 どの型でもキーになれるわけではなく、キーになれるのは Hashable プロトコルに適合した型のみ。 Swiftでキーとして使われるのは整数型、実数型、Bool型、文字列型、文字型などであるが、 実数には誤差があるので注意。 Hashableプロトコルでは hashValue: Int { get } というプロパティがある。 var d = ["Swift" : 2014, "Objective-C" : 1983] キーがString型で値がInt型である辞書を、変数dの型として宣言すると、次のようになる。 var d : [ String : Int ] // 変数の宣言 var d : Dictionary<String, Int> // 上記と同じ 変数の宣言と同時にイニシャライザを呼び出す。 var d = [ String : Int]() // イニシャライザの呼び出し var d = Dictionary<String, Int>() var d : [ String : Int ] = [ : ] // 型を指定した変数に空の辞書を代入 辞書は値型のデータである。 他の変数に代入したり関数への引数として渡したりする場合にはコピーが渡され、元の辞書の内容には影響がない。 辞書へのアクセス †辞書型の定数や変数に対して、キーを指定して値を取り出すことができる。 返り値はオプショナル型で、存在しない場合は nil が返る。 下の例では返り値は Int? 型 (Optional<Int>型)。 var d = ["Swift" : 2014, "Objective-C" : 1983] if let v = d["Swift"] { print(v) } // 2014 と表示される。キーが存在するので。 if let v = d["Phython"] { print(v) } // print()は実行されない。キーが存在しないので。 既に存在するキーの要素を削除するには、値として nil を代入する。 辞書がprint()で出力される順序は、Swiftの実装に依存する。 var e = ["Ruby: 1995] print(e) // ["Ruby": 1995] と表示される e["Java"] = 1995 e["Python"] = 1991 print(e) // ["Java": 1995, "Ruby": 1995, "Python": 1991] と表示される e["Java"] = nil print(e) // ["Ruby": 1995, "Python": 1991] と表示される キーにInt型を使うと、配列に近い使い方ができる。sparseなデータに対しては、配列よりも辞書の方がメモリ効率がよい。 辞書の比較 †辞書の比較 †辞書同士を比較するために演算子 == と != が使える。 同じキーの集合を持ち、同じキーに割り当てられている値が等しい場合に、辞書が等しいとみなされる。 値は互いに等しいかどうかを判断できる必要があり、Equatableプロトコルに適合している必要がある。 var a = [ "one": "I", "two": "II", "three": "III" ] let b = [ "two": "II", "one": "I" ] a == b // false a["three"] = nil a == b // true 辞書とfor-in文 †辞書とfor-in文 †辞書を for-in 文で、要素を1つずつ取り出しながら繰り返し処理を行うことができる。 要素をタプルで受けてもよい。 let dic = ["Mars": "火星", "Venus": "金星" ] for (en, ja) in dic { // タプルからデータを en と ja に取り出す print("\(en) = \(ja)") } for t in dic { // tはタプルが取り出される print("\(t.0) = \(t.1)") // タプルの要素に .0, .1 でアクセスする } 辞書の keys プロパティは、キーの集合 (CollectionTypeに適合した型)を取り出す。 また、 values プロパティは、値の集合 (CollectionTypeに適合した型)を取り出す。 for k in dic.keys { print("\(k)") // "Mars" "Venus"と各行に表示される。 } let planets = [String](dic.values); // 値からなる配列を作る print(planes) // ["火星", "金星"] と表示される。 辞書のメソッドとプロパティ †辞書のメソッドとプロパティ †以下では、キーの型を KeyType で、値の型をValueTypeで表している。
集合 †集合 (set) はコレクションの一種であるが、同一の要素を重複して格納できず、要素の順序に意味がないという点が特徴である。 要素の型は Hashable プロトコルに適合していなくてはいけない。 文字列を要素とする集合 var s: Set<String> // 変数の宣言 var t: Set<String> = [ "abc", "def", "ghi" ]; // 宣言と同時に配列リテラルを初期値として代入する Int型を要素とする集合 var a: Set<Int> = [] // 空で初期化する var b = Set<Int>() // 上と同じ var c = Set<Int>(0..<8) // SequenceType型を引数にできる 要素へのアクセス †集合は、配列と同じく SequenceType プロトコルと CollectionType プロトコルに適合しているので、 for-in 文で要素を取り出せる。 CollectionType プロトコルの first プロパティにより、 辞書の要素を1つ取り出すことができる(何が取り出されるかはわからない)。 var t = Set<Int>(0..<8) for i in t { print(i, terminator: " ") // 0 1 2 3 4 5 6 7 がバラバラな順番で表示される。 } print(t.first) // 0から7までのどれかの整数が表示される。 集合のメソッド †型パラメータ T は「集合の要素の型」、 型パラメータ S は「Tを要素とする SequenceType 型」を表すものとする。
|