Swift

Swift/基本的なデータ型

整数と実数

種類型名説明
符号付き整数Int(Int32またはInt64)
Int8, Int16, Int32, Int64ビット幅が指定された整数型
符号なし整数UInt(UInt32またはUInt64)
UInt8, UInt16, UInt32, UInt64ビット幅が指定された整数型
実数Double64ビット浮動小数点数
Float32ビット浮動小数点数
Float32, Float64, Float80ビット幅が指定された実数型

数値型のリテラル

  • 10進数では、数字と数字の間に_をいれて読み易くることができる(先頭以外)。
  • 0から始まっていても8進数ではない。
  • 16進数は 0x を前につける。文字の間に _ をいれて読み易くすることができる。
  • 8進数は 0o を前につける。文字の間に _ をいれて読み易くすることができる。
  • 2進数は 0b を前につける。文字の間に _ をいれて読み易くすることができる。
  • 10進数の実数は、eまたはEを使って10の冪乗倍を表現できる。
    1.23e1 (= 12.3)   1.23e8 (= 123000000)  1.23e-2 (= 0.0123)
  • 16進数でも実数値を書き表すことができる。pまたはPを使って2の冪乗倍を表す。
    0x1.8p0 (= 1.5)   0x1.8p1 (= 3.0)   0x1.8p-2 (= 0.375)

Swiftには暗黙の型変換はあにので、イニシャライザをつかって明示的に型変換を行う。

範囲型と区間型

パラメータ付き型指定演算子意味型T
半開区間型HalfOpenInterval<T>A..<BA<=x<BInt,UInt,Doube,Float,文字,文字列
開区間型CloseInterval<T>A...BA<=x<=B
範囲型Range<T>A..<BA<=x<BInt, UInt
A...BA<=x<=B

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"は表示されない
  • 区間型: 始点と終点の「間」自体を意味するデータ。
  • 範囲型: 始点と終点の間に存在し、数え上げることができるインスタンスの集合を扱うためのデータ。for-in 文で使うことができる。
    let range : Range<Int> = 0..<8    // 整数型の範囲
    for elm in range { print(elm) }   // 01234567 が表示される
    let intv = 0.0 ..< 8.0            // 実数型の区間
    for elm in intv { print(elm) }    // エラーで実行できない

配列

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型は、元の配列の一部を参照するために作られたデータ。 それぞれは別の配列なので、どちらかの内容を変更してももう一方に影響はない。

配列とプロトコル

  • Array型は CollectionTypeプロトコルの機能を備えている。 CollectionTypeプロトコルでは isEmptyというプロパティを持つ。
  • CollectionTypeは SequenceTypeプロトコルの機能を備えている。 SequenceTypeプロトコルは値を順番に取り出すことができる(for-in文が使える)。

配列のイニシャライザ
配列の型は、[Int]という書き方の他に、要素の値をパラメータとしてパラメータ付き型指定で記述することができる。

var a : Array<Int> = [ 2, 5, 8, 11, 7 ]
var s = Array<String>()

配列を生成する際に利用できるイニシャライザは次の通り。

  • init()
    空の配列を返す
  • init<S>(_ : S)
    引数としてSequenceType型のデータを指定できる。具体的には、範囲型や配列から取り出した部分れつ(ArrayTlice型)や文字列のcharactersプロパティの値などを指定できる。
    let seq = [Int](0 ..< 10)
    let chars = [Character]("abcd".characters)     // ["a","b","c","d"]
  • init(count:Int, repeatedValue: T)
    第1引数で指定した個数分、第2引数の要素を格納した配列を返す。
    var data = [Double](count:10, repeated&#86;alue:0.0)

配列のプロパティ

  • count: Int { get } --- 配列の要素数
  • first: T? { get } --- 配列が空でなければ最初の要素。空ならばnil
  • isEmpty: Bool { get } --- 配列の要素が0個かどうかを示す論理値
  • last: T? { get } --- 配列が空でなければ最後の要素。空ならばnil

配列のメソッド

  • mutating append(_: T)
  • mutating appendContentsOf<S>(_: S)
  • mutating insert(_: T, atIndex: Int)
  • mutating removeAll(keepCapacity:Bool = false)
  • mutating removeAtIndex(_: Int) -> T
  • mutating removeLast() -> T
  • reverse() -> [ T ]

可変個の引数が利用できる関数

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型のイニシャライザ

  • init() --- 空文字を生成する。""と同じ。
  • init<T>(_: T) --- 型パラメータTの示すデータ型を引数にする。用いられる型は型推論によって 自動的に判断されるのが普通である。
    let a = String(20001 - 10031)  // 整数から "9970" を生成する
    let b = String([6001, 5210])   // 整数の配列から "[6001, 5210]" を生成する
    let color:[Character] = ["初", "夢"]  // Character型の配列から
    let s = String(color)          // "初夢" を生成する
  • init(count: Int, repeatedValue: Character) --- 指定された文字をcount個含む文字列を生成する
  • init(count: Int, repeatedValue: UnicodeScalar) --- 同上

String型のプロパティ

  • isEmpty: Bool { get } --- 空文字列 "" かどうか
  • characters: String.CharacterView { get } --- 文字列に含まれる文字の集合を返す
  • unicodeScalars: String.UnicodeScalarView { get } --- 同上
  • utf8: String.UTF8View { get } --- 同上
  • utf16: String.UTF16View { get } --- 同上

String型の演算子 (Comparableプロトコルに適合している)

  • + --- String型の値を連結する
  • += --- String型の値を連結し、代入する
  • ==, != --- 2つの文字列を比較する。
  • <, >, <=, >= --- 2つの文字列を辞書順で比較する。

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 = "華"
Unicode&#83;calar型は相互に大小比較が可能であり、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
/ギ/モ/ー/ヴ/
/キ/゛/モ/ー/ウ/゛/

指定一の文字および部分文字列の取り出し方

  • subscript(i: Index) -> Chracter { get } --- 添字で指定した位置の文字を取り出す
  • subscript(subRange: Range<Index.) -> String { get } --- 指定した範囲の部分捩れつを取り出す
  • startIndex: Index { get } --- 文字列の最初の添字を取り出す
  • endIndex: Index { get } --- 文字列の最後の添字を取り出す

String.Index型は bidirectionalIndexTypeプロトコルに適合しているので、次のメソッドを持つ。

  • func successor() -> Self --- 1つ先のインデックス
  • func predecessor() -> Self --- 1つ前のインデックス
  • func advance<T>(_: T, _: T.Distance) -> T --- 指定した整数の分だけ参照位置を移動できる。 インデックス型の変数に対する ++, -- はそれぞれ successor(), predecessor() を呼び出す。
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型のメソッド

  • mutating append(_: Character) --- 引数の文字を、対象の文字列自体の末尾に追加する
  • mutating append(_: UnicodeScalar) --- 引数の文字を、対象の文字列自体の末尾に追加する
  • mutating appendContents&79;f<S>(_ : S) --- 引数の文字列を、対象の文字列自体の末尾に追加する
  • hasPrefix(_: String) -> Bool --- 対象の文字列の先頭部分が、引数の文字列と同じであればtrueを返す。
  • hasSuffix(_: String) -> Bool --- 対象の文字列の末尾部分が、引数の文字列と同じであればtrueを返す。
  • mutating insert(_: Character, atIndex: Index) --- 第1引数の文字列を、第2引数の位置挿入する。
  • mutating insertContentsOf<C>(_: C, atIndex: Index) --- 文字を要素とするCollectionType型の第1引数を、第2引数の位置挿入する。
  • mutating removeAtIndex(_: Index) -> Character --- 引数の指定する位置の文字を削除して返り値とする。
  • mutating removeRange(_: Range<Index>) --- 引数の指定する範囲の文字列を削除する。
  • mutating replaceRange(_: Range<Index>, with: C) --- 文字を要素とするCollectionType型の第1引数を、第1引数の指定する範囲の文字列と置き換える。

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で表している。

  • updateValue(_: Value&84;ype, forKey: KeyType) -> ValueTypeD --- 指定したキーに対応する値を、新しく指定した値で置き換える。キーに対応する値が存在していればその値が、存在していなければnilが返る。
  • removeValueFor&#75ey(_: Key&84;ype) -> ValueTypeD --- 指定したキーに対応する値を辞書から削除する。キーに対応する値が存在していればその値が、存在していなければnilが返る。
  • count: Int { get } --- 辞書の登録数を返す。

集合

集合 (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)   // Sequence&#84;ype型を引数にできる

要素へのアクセス

集合は、配列と同じく 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 型」を表すものとする。

  • func contains(_: T) -> Bool --- 引数を要素として含んでいるかを返す
  • mutating func insert(_: T) --- 引数を要素に加える。
  • mutating func remove(_: T) -> T? --- 要素に含まれていれば削除してその要素を、含まれていなければ nil を返す。
  • mutationg func removeFirst() -> T --- 最初の要素を削除して返す。
  • func isSubsetOf<S>(_: S) -> Bool --- 自身の集合が引数の部分集合かどうか調べる。
  • func union<S>(_: S) -> Set<T> --- 自身の集合と引数のunionの新しい集合を作って返す。
  • mutationg func unionInPlace<S>(_:S) --- 自身の集合に対して引数のunionを取る。
  • func subtract<S>(_: S) -> Set<T> --- 自身の集合と引数のsubtractの新しい集合を作って返す。
  • mutationg func subtractInPlace<S>(_:S) --- 自身の集合に対して引数のsubtractを取る。
  • func intersect<S>(_: S) -> Set<T> --- 自身の集合と引数のintersectの新しい集合を作って返す。
  • mutationg func intersectInPlace<S>(_:S) --- 自身の集合に対して引数のintersectを取る。
  • func exclusiveOr<S>(_: S) -> Set<T> --- 自身の集合と引数のexclusiveOrの新しい集合を作って返す。
  • mutationg func exclusiveOrInPlace<S>(_:S) --- 自身の集合に対して引数のexclusiveOrを取る。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-05-26 (木) 13:08:48 (1535d)