前を向くために Part3

プログラミング、音楽、外交問題、その他思いついたことを何でも公開

人生、前向きに生きたいもの。でも、何かと後ろ向きになりがちな自分がいるのです。前向きに生きるには、まず前を向かなければなりませぬ。じゃあ前を向くためにはどうしたらいいの?と日々悩んどります。これはその記録の一部です。

2014年11月02日のTweet

Swift言語ガイド 第3章 文字列と文字

  • 文字列型は String
  • 文字型は Character
  • String 型は参照型ではなく値型である(代入とか関数呼び出し時とかでは文字列がコピーされる。ただし本当に必要になるまでコピーはしないように最適化されてはいる)。
  • 文字列補間(String interpolation)が使える(\() のこと)。かっこ内では、エスケープしていないダブルクオート、エスケープしていないバックスラッシュ、および CR と LF は使用できない。
  • NSStringAPI がすべて利用可能。また NSString が使えるすべての APIString が使える。詳しくは “Using Swift with Cocoa and Objective-C” を参照。
  • String 型同士の結合は ++= でできる(既出)。

空文字列は空文字リテラル "" か新規文字列インスタンスを作成することで作成できる(つまり文字列インスタンスの初期値は空文字列ということ)。以下の2つは等価。


var emptyString = ""
var anotherEmptyString = String()

文字列が空文字列かどうかを調べるには Boolean プロパティ isEmpty を使う。


if emptyString.isEmpty {
println( "何もない。" )
}

文字列型は文字型の順序付きコレクションなので、ここの文字にアクセスするには for-in のような繰り返しが使える。


for character in "Dog! 犬!" {
println( character )
}

文字型の定数や変数を作るにも、"" を使う。この時、型を指定すること(でないとたぶん文字列型になる)。


let yenSign: Character = "\"

文字列型に文字型を結合するには文字列型の append メソッドを使う。この逆つまり文字型に文字列型や文字型を結合することはできない。文字型はあくまで1文字である。


let exclamationMark: Character = "!"
welcome.append( exclamationMark )

ユニコード

  • コード体系はユニコードで、U+0000-U+D7FF, U+E000-U+10FFFF が含まれるが、すべての文字が使えるわけではなく、文字のないコード(将来のために予約されていたりする)もある。またサロゲートペアはサポートされないので U+D800-U+DFFF は使用できない。
  • エスケープすれば以下の特殊文字も使える。
    • \0(null 文字)
    • \\(バックスラッシュ)
    • \t(水平タブ)
    • \n(LF)
    • \r(CR)
    • \"(ダブルクオート)
    • \'(シングルクオート)
  • \u{ n } で表されるユニコード(n は1桁から8桁の16進数)。ユニコードを数値で指定する場合はこのフォーマットを使う("\u{24}" とか)。

拡張書記素クラスタ(Extended Grapheme Cluster)

拡張書記素クラスタとは、一つかそれ以上のユニコードコードのシーケンスで、結合して一つの文字を作成するものである。日本人にわかりやすい例だと、ひらがな/カタカナの濁点や半濁点などがある。

拡張書記素クラスタの文字は、Swift では1文字として扱われるので Character 型に代入できる。


let enclosedOne: Character = "\u{31}\u{20DD}"

地域インディケータシンボル Regional Indicator Symbol も結合されて1文字として扱うことができる。


let us: Character = "\u{1F1FA}\u{1F1F8}"

文字数のカウント

  • 文字列の文字数を得るには、グローバル関数 countElements を呼び出す。
  • 拡張書記素クラスタがあるので、文字数は、実際に文字を構成しながら数えてみないとわからない。単純なバイト数からはわからないのである。
  • ゆえに、長い文字列の文字数をカウントする場合などは注意のこと。
  • countElements の戻り値は、NSStringlength プロパティとは異なる。NSString の長さは UTF-16 表現での16ビットコード単位に基づいており、拡張書記素クラスタを含む文字の数ではない。このため、NSStringlength プロパティは Swift では utf16Count と呼ばれている。

文字列の比較

テキスト表現の値の比較には、3つの種類がある。

文字列および文字が等しいか異なるかは、等価比較演算子==)または不等比較演算子!=)を用いることができる。

文字列および文字の比較は、拡張書記素クラスタを考慮して比較され、もし言語的に等しくかつ見た目が等しいならば、その構成がことなるユニコード数であっても等しいとみなされる。たとえば、ラテン文字のアキュート付き小文字 é(U+00E9)はラテン文字の小文字 e(U+0065)に合成アキュートアクセント(U+0301)を続けたものは、等しいとみなされる。ひらがな、カタカナの濁点などの扱いも同じなので、要注意である。しかし、半角の A と全角の A は違うとみなされる。言語体系が違うから?よくわからない。


let katakana_ga = "\u{304C}"
let katakana_combined_ga = "\u{304B}\u{3099}"
if katakana_ga == katakana_combined_ga {
println( "等しい!" ) // 等しい!
}

let zenkaku_A ="A"
let hankaku_A = "A"
if zenkaku_A == hankaku_A {
println( "等しい!" )
} else {
println( "これは違う!" ) // こっちに分岐する。
}

文字列全体として等しいか異なるか以外に、以下の2つの等価性を比較することができる。これの比較も上記と同様の比較を行うので、やはり要注意である。

  • 前置等価性は文字列型のメソッド hasPrefix を使う。引数の文字列が文字列先頭にあれば真、なければ偽が返る。
  • 後置等価性は文字列型のメソッド hasSuffix を使う。引数の文字列が文字列最後にあれば真、なければ偽が返る。

文字列のユニコード表現

エンコーディングUTF-8UTF-16UTF-32
プロパティutf8utf16unicodeScalars
プロパティの型String.UTF8ViewString.UTF16ViewUnicodeScalarView
取り出した値の型UInt8UInt16UnicodeScalar, さらに value プロパティで取り出すと UTF32

なお、ユニコードはビッグエンディアンであるという決まりがある。

(第3章 文字列と文字 終わり)

Swift言語ガイド第2章基本演算子

第1章に続けて第2章も要約。C と同じところはバッサリ省略している。Swift やろうという人なら C は知っているだろうということで。

用語 Terminology

演算子は単項演算子か、2項演算子か、3項演算子である。

  • 単項演算子は一つのターゲットに作用する(-a とか)。単項前置演算子はターゲットの直前に現れ(!a とか)、単項後置演算子はターゲットの直後に現れる(i++ とか)。
  • 2項演算子は二つのターゲットに作用する(2 + 3 とか)。二つのターゲットの間に現れるので、これは中置である。
  • 3項演算子は三つのターゲットに作用する(a ? b : c)。C と同様、3項演算子は一つだけである。

演算子が作用する値はオペランドと言う。

代入演算子

タプルにも使える。C や Objective-C と違って、代入演算子それ自身は値を返さない(if x = y は誤り)。この特徴は代入演算子=)を等値演算子==)が意図されるところに間違って使われるのを予防する。


let b = 10
var a = 5
a = b
let ( x, y ) = ( 1, 2 )

算術演算子

以下の4つはすべての数値型をサポートする。

  • 加算(+
  • 減算(-
  • 乗算(*
  • 除算(/

C や Objective-C と違って、Swift のデフォルトでは算術演算子での値のオーバーフローを許さない。オーバーフローを許す場合はオーバーフロー演算子a &+ b とか)を使う必要がある。これについては詳しくは後述。

加算演算子は文字列の結合にも使える。

剰余演算子

  • % を使う(9 % 4 とか)。
  • a = ( b × 倍数 ) + reminder
  • a が負の場合は倍数も reminder も負になる。
  • b が負の場合は正と同様に扱われる(a % ba % -b も答えは一緒)。
  • 浮動小数点にも使える(8 % 2.50.5 になるとか)。

インクリメント演算子とデクリメント演算子

  • C と同様、インクリメント演算子++)とデクリメント演算子--)がある。
  • どの整数型あるいは浮動小数点型にも使える。
  • 値を返す。
  • 前置演算子としても後置演算子としても使える。単に値を1だけ増やすあるいは減らすという意味ではどちらも同じ結果になるが、値を返す点に注目すると、前置演算子の場合には、値を返す前にインクリメントあるいはデクリメントされる。後置演算子の場合には、値を返した後にインクリメントあるいはデクリメントされる。
  • 特段の理由がない限り、常に前置演算子を使うことをアップルは推奨している。


var a = 0
let b = ++a // a も b も 1
let c = a++ // a は 2、c は 1

単項プラス演算子、単項マイナス演算子

期待通りに働く。リテラルだけでなく定数や変数にも使える。空白文字を挟んではならない。

複合代入演算子

+= とか -= のこと。C と同じだが、値は返さないので注意。インクリメント・デクリメント演算子と混同しないように。

比較演算子

  • 等しい(a == b
  • 等しくない( a != b
  • 大きい(a > b
  • 小さい(a < b
  • 大きいか等しい(a >= b
  • 小さいか等しい(a <= b

上記に加えて、Swift では2つのアイデンティティ演算子===!==)を提供する。これらは2つのオブジェクトの参照が同じオブジェクトインスタンスを参照しているかどうかをテストする演算子である。詳細は「クラスと構造体」のところで述べる。

それぞれの比較演算子は、みんな Bool 値を返す。

3項条件演算子

C と同じ。使いすぎに注意。

nil 結合演算子 Nil Coalescing Operator

  • a ?? b と書く。
  • a は常に Optional 型である。
  • b の型は a に保存されている型と一致しなければならない。
  • Optional a が値を持つならばその値を返し、anil ならばデフォルト値b を返す。
  • 次の3項条件演算式と等価。a != nil ? a! : b

範囲(レンジ)演算子

  • 閉じた範囲演算子 a...ba から b までの範囲を定義する。ab より大きくてはならない。
  • 半開き範囲演算子 a..<ba から b までの範囲を定義するが、b は含まない。閉じた範囲演算子と同じく ab より大きくてはならない。
  • for 文の範囲指定などに使うと便利。
  • for index in 1...5 {
    	println( index )
    }
    
    let names = [ "あんな", "あきら", "ブン", "ジョー" ]
    let count = names.count
    for i in 0..< count {
    	println ( names[ i ] )
    }
    

    論理演算子

    C と同様、以下の3つがある。

    論理否定は前置演算子なので間に空白文字があってはならないことに注意

    論理演算子の合成

    複数の論理演算子が連なっている時のこと。優先順位は C と同じ。かっこが優先されるのも同じ。読みやすいようにかっこを入れようというアップルの主張もある。

    (第2章基本演算子終わり)

Swift言語ガイドの第1章を要約してみた

The Swift Programming Language の Language Guide を読んでの要約。逐語訳の翻訳ではないけど、漏れはないと思う。

基本事項

定数と変数

  • 定数の宣言には let
  • 変数の宣言には var
  • 1行に複数個書ける。
  • 型も宣言する場合はコロン : に続けて型名を書く。


let maxLoginAttempts = 10
var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0
var message: String
var red, green, blue: Double

アップルは定数の使用を強く推奨。

  • 定数名や変数名には、ユニコード文字も含めて、ほぼどんな文字も使える。
  • ひらがな、カタカナ、漢字も使える。
  • 空白文字、数学記号、矢印、罫線文字(表や箱を作るのに使うやつ)、ユニコードの私的利用領域は使えない。
  • 先頭文字に数字は使えない(2番目以降では使える)。
  • 1度宣言した定数や変数を同じ名前で再度宣言したり型を変更することはできない。定数を変数に変更したり、その逆もできない。
  • Swift予約語と同じ名前の定数や変数を作りたい場合は、その名前をバッククウォート(`)で囲む(けどよほどのことがない限りやらないほうがよい)。

printlnprint を使えば、C言語などと同様に定数や変数を出力できる。Xcode においては、それはコンソールに出力される。Cocoa の NSLog みたいな詳細なロギングもできる。

Swift は、文字列置換(string interpolation)を用いることにより、長い文字列の中に定数名や変数名をプレースホルダーとして入れ込んで、出力時にその時点での定数や変数の値を出力させることができる。これをやるには \() を使う。

println( "現在の friendlyWelcome の値は \( friendlyWelcome )" )

コメント

コメントは、多くの言語に採用されている、1行コメント//複数行コメント /* */ が使える。複数行コメントは、C言語とは違ってネストできる。コメントを含む大きなブロックをコメントアウトするときなんかに便利。

セミコロン

行末のセミコロンは不要。ただし、1行に複数の文を書く場合は、文の区切りとして必要。

整数

  • Swift には 8、16、32、64bit の符号付き整数と符号なし整数がある(Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64)。型名なので大文字で始まるのに注意。
  • 整数型の最大値または最小値にアクセスするには .min.max が使える。
  • 特段の理由がない限り、通常は単なる Int を使うべし。たとえ負の値は取らないとわかっている場合であっても。Int のビット長は実行するプラットフォームのワード長に依存する。Int だけを使っていれば、整数型の宣言のたびに何ビットにするか悩まないですむし、型変換もしなくて済む。

浮動小数

Swift でも符号付き浮動小数点型として FloatDouble があり、Float は32ビット、Double は64ビットである。Float の10進数部分は6字くらい、Double は最低でも15字ある。どっちを使うかは整数のように単純ではなく、その時に必要な値の範囲や状況によるらしい。ちなみに Swift 標準ライブラリのデフォルトは Double である。

型セーフと型推論

  • Swift は型セーフな( type safe )言語である。であるからコンパイル時に型チェックが行われる。
  • これは別にすべての宣言において型も宣言せよということではない。
  • Swift型推論をやってくれるし、それで普通は適切に処理される。このおかげで型宣言は C や Objective-C よりずっと少なくて済む。
  • 定数宣言や変数宣言時に初期値を与える場合は特に便利。整数の初期値なら型推論の結果は Int になるし、浮動小数点数の初期値なら Double になる。

数値リテラル

整数リテラルは以下の4つがある。

  • プレフィックスなしの10進数(17 とか)
  • 0b というプレフィックスの2進数(ob10001 とか)
  • 0o というプレフィックスの8進数(0o21 とか)
  • 0x というプレフィックスの16進数(0x11 とか)

浮動小数リテラルは以下の2つがある。

  • プレフィックスなしの10進数。この場合、指数部分 e を書くとそれは10の累乗になる(1.25e2 = 125.0 とか)。
  • 0x というプレフィックスの16進数。この場合、指数部分は p となり2の累乗になる(0xFp2 = 15 * 22 = 60.0 とか)

数値リテラルは、整数であれ浮動小数点数であれ、読みやすくするためにゼロパディングとアンダースコアが使える。


let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1

数値型変換

くどいようだが特段の理由がない限り、整数には Int を使うこと。

整数型の様々な型は、型によって保存できる値の範囲が異なるので、数値型変換はケースバイケースで対応する必要がある(ので隠れた変換エラーを予防することができ、明示的に型変換する助けになる、らしい)。以下の例参照。


let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand _ UInt16( one )

こういうことが可能なのは、実は UInt16 が UInt8 を受け入れるイニシャライザを持っているからであって、何でもかんでも型名を書いてかっこでくくればよいというものではない。イニシャライザが受け入れ可能な型に限られるのである。既存の型に新しい型を受け入れるイニシャライザを追加したりするには「拡張 Extension」が必要である(「拡張 Extension」参照)。

整数と浮動小数点の変換は明示的に行う必要がある。以下の例では IntDouble に型変換しているが、 Double Int に変換する場合は、常に小数点以下が切り捨てられる(3.75-3.753 になる)。


let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double( three ) + pointOneFourOneFiveNine

エイリアス Type Aliases

エイリアスは文字通り型の別名。typealias というキーワードを使って定義する。これは、既存の型に対し、文脈上もっと意味のある名前をつけるときなんかに便利(かもしれない)。


typealias AudioSample = UInt16

ブーリアン Booleans

型名は Bool で、これは値として truefalse という定数値を取る。Boolean 値は if 文みたいな条件文を扱う時に特に便利(と言うかそういうところで使う)。

タプル Tuples

Tuple は複数の値をひとつの複合値にグループ化するものである。Tuple 内の値はどんな型でもよく、同じ型である必要もない。中の値に名前をつけることもできる。個々の定数や変数に分解も可能。分解時に不要な部分はアンダースコアを使うことができる。また、ゼロから始まる番号でもアクセス可能である。


let http404Error = ( 404, "Not Found" )
let ( statusCode, statusMessage ) = http404Error
println( ”ステータスコードは \( statusCode ) でメッセージは \( statusMessage )" )
let ( justTheStatusCode, _ ) = http404Error
let anotherStatusCode = http404Error.0
let http200Status = ( goodStatus: 200, description: "OK" )
println( "ステータスコードは \( http200Status.goodStatus )" )

Tuple は特に関数の戻り値として使うときに便利である。詳しくは後述。また、一時的に関連する値をまとめておくのにも便利。一時的でない場合はクラスや構造体を使うべし。

オプショナル Optionals

Optional は値がまったくないかもしれないという場合に使う。つまり、以下の2通りの状態が取れる。これはどんな型にも使える。

  • 値があり、その値は x である。
  • 値がまったくない。

値がまったくないという状態を表すために、nil という特別な値を導入する。nil は Optional にのみ利用可能で、Optional でない定数や変数に代入することはできない。もしある定数や変数がある条件の元では値がまったくとれないのであれば、常にそれは適当な型とともに Optional として宣言すべし。これからもわかるように、SwiftnilObjective-Cnil とは違う。デフォルトの値なしに Optional な定数や変数を定義すると、それは自動的に nil がセットされる。Optional を定義するには、型名に続いて ? をつける。


var surveyAnswer: String?

if 文と強制アンラップ Forced Unwrapping

Optional が値を持っているかどうかを調べるには if 文を使って nil と比較する。もし値を持っていれば、それは nil ではない。この結果、確かにこの Optional は値を持っているということが確実になれば、Optional の名前の最後にびっくりマーク(!)を付け加えることにより、その値にアクセスすることができる。これを強制アンラップ forced unwrapping と言う。もし値のない Optional を強制アンラップすると、ランタイムエラーになる。なので ! を使って強制アンラップをする前に、常に Optional が nil ではない値を持っていることを確認するようにしたほうがよい。


if convertedNumber != nil {
println( "convertedNumber は値 \( convertedNumber! ) を持つ。" )
}

オプショナルバインディング Optional Binding

Optional binding は、Optional が値を持つかどうかを調べ、もし持つならその値を一時的な定数か変数として利用可能にするのに使われる。Optional binding は、if 文と while 文で使える。以下の形をとる。

  1. もし「何かの Optional」が値を持っている場合、Optional から定数への代入は成功し、定数はその値を持つようになる。
  2. if 文の条件は true となり、文1が実行される。この文1の中では定数が使える。
  3. Optional が値を持っていない場合は、定数への代入は成功せず、else があれば、else にある文2が実行される。ただし定数は使えない。else がなければ if 文を抜ける。Optional Binding を使えば、強制アンラップを使う必要はなくなる。


if let 定数 = 何かの Optional {
文1
} else {
文2
}

以下の実例のほうがわかりやすいかもしれない。


if let actualNumber = possibleNumber.toInt() {
println( "\'\( possibleNumber )\' は値 \( actualNumber ) を持つ。" )
} else {
println( "\'\( possibleNumber )\' は変換できなかった。" )
}

Optional Binding には、定数も変数も使える。もし上記の例の最初の分岐の中で actualNumber を変更したりしたいのであれば、if var actualNumber のように書けばよい。

暗黙にアンラップされたオプショナル Optional

時として、プログラムの構造上、Optional が最初に値を持った後は常に値を持つということがある。常に値を持つと仮定できるので、アクセスするたびに値があるかどうか確認してアンラップするというのはない方が便利である。こういう Optional は暗黙にアンラップされた Optional と定義される。暗黙にアンラップされた Optional は、宣言時にはてなマークではなくびっくりマークを用いる。

が、何が嬉しいのかよくわからない。宣言時からそれ以降ずっと値を持つのなら、別に Optional でなくても普通の変数や定数でいいんじゃないの?という気がするんだけど……。

アサーション

主にデバッグ用。論理条件が真であることを評価するランタイムチェックである。本質的な条件が満足されているかどうかを、その後を実行する前に確認するのに使われる。もし真なら、普通にその後のコードを実行し続けるが、もし偽なら、実行は停止し、アプリケーションは終了する。Xcode で開発する場合、アサーションに引っかかると、どこで引っかかったのかがわかる。

アサーションを使う場合は、グローバルな assert 関数を呼び出す。関数には、truefalse を評価する式と、false の時に出すメッセージを渡すが、メッセージは省略可能。


let age = -3
assert( age >= 0, "人間の年齢は0より小さくはなり得ない" )

どういう場合にアサーションを用いるかの指針が出ている。

  • 整数の添字が大きすぎたり小さすぎたりする可能性がある場合
  • 関数に渡す引数の値が不正で関数がタスクを完了できないかもしれない場合
  • Optional 値が今は nil だけれども、その後のコードでは nil でないことが本質的である場合

(第1章基本事項終わり)

2014年11月01日のTweet

Swift言語の識別子についての覚え書き

識別子は A から Z の大文字または小文字、アンダースコア( _ )、ユニコード基本多言語面Basic Multilingual Plane, BMP)にある非複合アルファニューメリック文字、私用領域(Private Use Area)以外にある基本他言語面外の文字で始まる。最初の文字の後ろは、数字と複合ユニコード文字も使える。

予約語を識別子として使いたい場合は、バッククウォート(`)で前後を挟む。例えば、class は有効な識別子ではないが、`class` は有効な識別子である。バッククウォート自身は識別子の一部とはみなされない。`x`x は同じ意味である。

明示的な引数名のないクロージャの中においては、引数は暗黙に $0, $1, $2, ... と命名される。これらの名前はクロージャのスコープ内において有効な識別子である。

まとめ


identifieridentifier-head identifier-charactersopt
identifier → `identifier-head identifier-charactersopt`
identifierimplicit-parameter-name
identifier-listidentifier | identifier , identifier-list
identifier-head → A から Z の大文字または小文字
identifier-head → _
identifier-head → U+00A8, U+00AA, U+00AD, U+00AF
identifier-head → U+00B2-U+00B5, U+00B7-U+00BA, U+00BC-U+00BE
identifier-head → U+00C0-U+00D6, U+00D8-U+00F6, U+00F8-U+00FF
identifier-head → U+0100-U+02FF
identifier-head → U+0370-U+167F
identifier-head → U+1681-U+180D, U+180F-U+1DBF
identifier-head → U+1E00-u+1FFF
identifier-head → U+200B-U+200D, U+202A-U+202E
identifier-head → U+203F-U+2040, U+2054
identifier-head → U+2060-U+206F
identifier-head → U+2070-U+20CF, U+2100-U+218F
identifier-head → U+2460-U+24FF, U+2776-U+2793
identifier-head → U+2C00-U+2DFF, U+2E80-U+2FFF
identifier-head → U+3004-U+3007, U+3021-U+302F, U+3031-U+303F
identifier-head → U+3040-U+D7FF
identifier-head → U+F900-U+FD3D, U+FD40-U+FDCF
identifier-head → U+FDF0-U+FE1F, U+FE30-U+FE44
identifier-head → U+FE47-F+FFFD
identifier-head → U+10000-U+1FFFD
identifier-head → U+20000-U+2FFFD
identifier-head → U+30000-U+3FFFD
identifier-head → U+40000-U+4FFFD
identifier-head → U+50000-U+5FFFD
identifier-head → U+60000-U+6FFFD
identifier-head → U+70000-U+7FFFD
identifier-head → U+80000-U+7FFFD
identifier-head → U+90000-U+9FFFD
identifier-head → U+A0000-U+AFFFD
identifier-head → U+B0000-U+BFFFD
identifier-head → U+C0000-U+CFFFD
identifier-head → U+D0000-U+DFFFD
identifier-head → U+E0000-U+EFFFD
identifier-character → 数字の 0 から 9
identifier-character → U+0300-U+036F
identifier-character → U+1DC0-U+1DFF
identifier-character → U+20D0-U+20FF
identifier-character → U+FE20-U+FE2F
identifier-characteridentifier-head
identifier-charactersidentifier-character identifier-charactersopt
implicit-parameter-name$10進数

注) 実際の文字は Unicode一覧 0000-0FFF などを参照のこと。U+0000-U+00FF についてのみ以下に表示する。

どこでも使える文字
2文字目以降で使える文字
使えない文字


















U+0123456789ABCDEF
0000NULSOHSTXETXEOTENQACKBELBSHTLFVTFFCRSOSI
0010DLEDC1DC2DC3DC4NAKSYNETBCANEMSUBESCFSGSRSUS
0020(空白)!"#$%&'()*+,-./
00300123456789:;<=>?
0040@ABCDEFGHIJKLMNO
0050PQRSTUVWXYZ[\]^_
0060`abcdefghijklmno
0070pqrstuvwxyz{|}~DEL
0080PADHOPBPHNBHINDNELSSAESAHTSHTJVTSPLDPLURISS2SS3
0090DCSPU1PU2STSCCHMWSPAEPASOSSGCISCICSISTOSCPMAPC
00A0NBSP¡¢£¤\¦§¨©ª«¬SHY®¯
00B0°±²³´µ·¸¹º»¼½¾¿
00C0ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
00D0ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
00E0àáâãäåæçèéêëìíîï
00F0ðñòóôõö÷øùúûüýþÿ

ひらがな、カタカナは U+3040〜30FF あたりだし、漢字とかも使えるから、識別子に日本語名を付けるというのも可能だけど、どうなんだろうなー。使うかな? 日本人は結局、先頭文字はアルファベットかアンダースコアで、2文字目以降はそれに加えて数字も使えるということでいいんじゃないの?という気がする…

Swift言語を超抄訳してみた

アップルが無償で公開している “Swift Programming Language” の中の “A Swift Tour” を超抄訳してみた。

定数、変数、オプショナル、タプル

定数は let を、変数は var を付ける。型は推測される。


let myConstant = 42
let myFloat = 42.0
var myVariable = 42

明示的に型を書く場合はコロン : の後に型名を書く。


let myDouble: Double = 42

オプショナル Optional は、特定のある値を持つか、または値を持たないという意味で nil を持つ。nil 値を取れる変数とも言える。宣言する場合には型名の後ろに ? を書く。


var optionalString: String? = "42"
optionalString = nil

タプル Tuple は複数の値の集まりである。中の要素の型が違ってもよい。要素を参照するには、名前か数字を使う。


let http404Error = ( 404, "Not Found" )
http404Error.0
http404Error.1

var httpError: ( code: Int, message: String)
httpError = http404Error
httpError.code
httpError.message

なお、値は自動的には型変換されないので、違う型に変換する必要がある場合は、明示的に型変換する。これは数値型同士でも必要。

let label = "幅は"
let width = 94
let widthLabel = label + String( width ) // ←型変換

ただし、文字列に何か値を埋め込む場合はバックスラッシュ+かっこ \() が使えるので便利。これを使えば明示的な型変換は不要。かっこの中では計算もできる。

let apples = 3
let oranges = 5
let appleSummary = "私は \( apples ) 個のリンゴを持っている。"
let fruitSummary = "私は \( apples + oranges ) 個の果物を持っている。"

配列とディクショナリ

配列やディクショナリを作るには大かっこ(ブラケット) [] を使う。ディクショナリとは、言ってみれば名前・値ペアのこと。その記法が配列と同じというだけの話。添字が文字列の配列とも言える。

var todaysShopping: [ String ]
var shoppingList = [ "魚", "水", "花", "インク" ]
shoppingList[ 1 ] = "水ボトル1本"
todaysShopping = shoppingList

var occupations = [
"まる子": "キャプテン",
"カイリ": "メカニック",
]
occupations[ "じゅん" ] = "広報"

空の配列やディクショナリを作るには、[][:] を使う。

shoppingList = []
occupations = [:]

フロー制御

条件分岐には ifswitch を、ループには for-inforwhiledo-while を使う。条件の部分にかっこを使うかどうかはどっちでもいい。ボディの部分に中かっこを付けるのは必須。

let individualScores = [ 75, 43, 103, 87, 12 ]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
teamScore

注)最後に teamScore とだけ書いてあるのは Xcode のプレイグラウンド内で変数の値を簡単に見るための方法である。

if

if 文において、条件は Boolean 式でなければならない。これはつまり if score {... はエラーということである。ゼロとの暗黙の比較は無い。

値が無いかもしれない場合には iflet を一緒に使うこともできる。こうした値はオプショナルが代表的である。

var optionalName: String? = "アップルのジョン"
var greeting = "こんにちは!"
if let name = optionalName {
greeting = "こんにちは, \( name )"
}

上記のコードで、もしオプショナルの値が nil の場合は、条件は false となり、ボディ内のコードはスキップされる。そうでなければ、オプショナルの値は let の後の定数に代入され、その値はボディブロックで使うことができる。

switch

スイッチ switch は、別に整数に限らず、またイコールかどうかにも限らず使える。default は必須。

let vegetable = "赤コショウ"
switch vegetable {
case "セロリ":
let vegetableComment = "レーズンを乗せるとおいしい。"
case "きゅうり", "クレソン":
let VegetableComment = "サンドウィッチに良い。"
case let x where x.hasSuffix( "コショウ" ):
let vegetableComment = "これ辛い \(x) かな?"
default:
let vegetableComment = "みんなスープには良い。"
}

let でパターンの比較部分に合致する定数へ代入するときに使えることとその使い方に注目。

合致する switch case の中のコードを実行した場合、プログラムはスイッチ文から抜け、次のケースを実行することはない。なので break を明示的に case の最後につける必要はない。

for

for-in においてディクショナリーを使う場合、ディクショナリーは順序のないコレクションなので、ループを実行する順序は不定である。

let interestingNumbers = [
"素数": [ 2, 3, 5, 7, 11, 13 ],
"フィボナッチ": [ 1, 1, 2, 3, 5, 8 ],
"2乗": [ 1, 4, 9, 16, 25 ],
]
var largest = 0
for ( kind, numbers ) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
largest

while, do-while

while (と do-while)は条件が変わるまでコードブロックを繰り返すのに使える。ループの条件は最後でもよく、この場合、ループは最低1回は実行される。

var n = 2
while n < 100 {
n = n * 2
}
n

var m = 2
do {
m = m * 2
} while m < 100
m

..< と ...

ループのインデックスのレンジを指定したり、明示的に初期化したり条件を付けたり増分を指定するのに、..<... という範囲(レンジ)演算子が使える。以下の3つのループは同じことをしている。

var firstForLoop = 0
for i in 1..<4 {
firstForLoop += i
}
firstForLoop

var secondForLoop = 0
for var i = 1; i < 4; ++i { // この場合は ++i でも i++ でも同じで、値は 1, 2, 3 を取る。
secondForLoop += i
}
secondForLoop

var thirdForLoop = 0
for i in 1...3 {
thirdForLoop += i
}
thirdForLoop

関数とクロージャ

関数を宣言するには func を使う。呼び出すには関数名に続けてかっこ内に引数のリストを入れる。関数の戻り値の型と引数の名前や型を分離するには -> を使う。

func greet( name: String, day: String ) -> String {
return "Hello \( name ), today is \( day )."
}
greet( "Bob", "Tuesday" )

関数から複数の値を返す場合などにはタプルを使う。

func calculateStatistics(scores: [Int] ) -> ( min: Int, max: Int, sum: Int ) {
var min = scores[ 0 ]
var max = scores[ 0 ]
var sum = 0

for score in scores {
if score > max {
max = score
else if score < min {
min = score
}
sum += score
}

return ( min, max, sum )
}
let statistics = calculateStatistics( [ 5, 3, 100, 3, 9 ])
statistics.sum
statistics.2

関数は、可変の数の引数を取ることもでき、それらは配列としてまとめられる。

func sumOf( numbers: Int... ) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}

sumOf()
sumOf( 42, 597, 12 )

関数はネスト可能。ネストされた内側の関数は外側の関数の変数等にアクセスすることができる。長かったり複雑だったりする関数を分割してわかりやすくすることにも使える。

func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()

関数はファーストクラスな型である。つまり、関数は、別の関数を戻り値として返すことができるということである。

func makeIncrementer() -> ( Int -> Int ) {
func addOne( number: Int) -> Int {
return 1 + number
}
return addone
}
var increment = makeIncrementer()
increment( 7 )

関数は別の関数を引数のひとつとして取ることができる。

func hasAnyMatches( list: [ Int ], condition: Int -> Bool ) -> Bool {
for item in list {
if condition( item ) {
return true
}
}
return false
}
func lessThanTen( number: Int ) -> Bool {
return number < 10
}
var numbers = [ 20, 19, 7, 12 ]
hasAnyMatches( numbers, lessThanTen )

関数は実はクロージャ、つまり後で呼び出すことができるコードブロックの特別なケースである。クロージャのコードは、クロージャが作られた時のスコープで利用可能な変数や関数などに、たとえそのクロージャの実行時に違うスコープであっても、アクセスすることができる。例としてあげられるのはネストされた関数である。クロージャは、中かっこで囲むことで、名前無しで書くことができる。引数と戻り値の型をボディから分離するには in を使う。

numbers.map({
( number: Int ) -> Int in
let result = 3 * number
return result
})

クロージャはもっと簡潔に書く方法がいくつかある。クロージャの型が、デリゲートのコールバックのようにすでにわかっている場合は、引数の型、戻り値の型、あるいはその両方を省略することができる。文が1つのクロージャは暗黙としてその文の値を返す。

let mappedNumbers = numbers.map({ number in 3 * number })
mappedNumbers

引数には、名前ではなく番号で参照することもでき、これは特に非常に短いクロージャで便利である。ある関数への最後の引数として渡されたクロージャはかっこのすぐ後に現れても良い。

let sortedNumbers = sorted( numbers ) { $0 > $1 }
sortedNumbers

オブジェクトとクラス

クラスを作るには、class の後にクラス名を続ける。クラス内のプロパティの宣言は、それがクラスのコンテキストの中であるという点を除けば、定数や変数と同じ方法で書ける。同様に、メソッドと関数も、同じ方法で書ける。

class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \( numberOfSides ) sides."
}
}

クラスのインスタンスを作るには、クラス名の後ろにかっこを書く。インスタンスのプロパティやメソッドにアクセスするにはドット記法を用いる。

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

上のバージョンの Shape は重要なもの、つまりインスタンスが作られた時にクラスをセットアップするイニシャライザが欠けている。それを作る場合は init を使う。

class NamedShape {
var numberOfSides: Int = 0
var name: String

init( name: String) {
self.name = name
}

func simpleDescription() -> String {
return "A shape with \( numberOfSides) sides."
}
}

self はこういう時にこう使うという例である。プロパティはどれも値を持つ必要があるが、それは numberOfSides のように宣言時に初期化するか、またはイニシャライザの中で行う。

オブジェクトが解放される前に何かクリーンアップが必要な場合は、deinit を使ってデイニシャライザを作る。

サブクラスは、サブクラス名の後にコロンを続けてスーパークラス名を含める。クラスを作るのにスーパークラスはあってもなくても良い。

スーパークラスの実装をオーバーライドするサブクラスのメソッドは、override とマークを付ける。これがないとコンパイルエラーになる。また、実際にはオーバーライドしていないメソッドoverride を付けてもコンパイルエラーになる。

class Square: NamedShape {
var sideLength: Double

init( sideLength: Double, name: String ) {
self.sideLength = sideLength
super.init( name: name )
numberOfSides = 4
}

func area() -> Double {
return sideLength * sideLength
}

override func simpleDescription() -> String {
return "A square with sides of length \( sideLength )."
}
}
let test = Square( sideLength: 5.2, name: "my test square" )
test.area()
test.simpleDescription()

単純なプロパティに加えて、プロパティはゲッターとセッターを持てる。

class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0

init( sideLength: Double, name: String ) {
self.sideLength = sideLength
super.init( name: name )
numberOfSides = 3
}

var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newNalue / 3.0
}
}

override func simpleDescription() -> String {
return "An equilataral triangle with sides of length \( sideLength )."
}
}
var triangle = EqualateralTriangle( sideLength: 3.1, name: "a triangle" )
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength

perimeter のセッターの中に、新しい値が暗黙の名前 newValue を持っているが、これは明示的に set の後にかっこでくくって名前を付けることもできる。

イニシャライザが3つの異なるステップを持っていることに注目。

  1. サブクラスで宣言されているプロパティの値をセットする。
  2. スーパークラスのイニシャライザを呼び出す。
  3. スーパークラスで定義されているプロパティの値を変更する。メソッドやゲッターやセッターを使うその他の追加セットアップはこの時点で行うことができる。


もし、プロパティを計算する必要はないけれども、値をセットする前や後にコードを走らせる必要がある場合は、willSetdidSet を使う。例えば、下の例では、正三角形の1辺の長さが常に正方形の1辺の長さと同じであることを確実にする。

class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init( size: Double, name: String ) {
square = Square( sideLength: size, name: name )
triangle = EquilateralTriangle( sideLength: size, name: name )
}
}
var triangleAndSquare = TriangleAndSquare( size: 10, name: "another test shape" )
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square( sideLength: 50, name: "larger square" )
triangleAndSquare.triangle.sideLength

クラスにおけるメソッドは、関数との重要な違いが一つある。引数の名前は、関数においては関数の中でのみ使用されるが、メソッドにおいてはメソッドを呼び出す際にも使われるというということだ(1番目の引数を除く)。デフォルトでは、メソッドは引数名を呼び出し時と内部とで同じ名前で持つが、内部だけで使う2番目の名前を指定することもできる。

class Counter {
var count: Int = 0
func incrementBy( amount: Int, numberOfTimes times: Int ) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy( 2, numberOfTimes: 7 )

オプショナル値の場合は、メソッド、プロパティ、添字などのような演算の前に ? を書くことができる。もし ? の前の値が nil ならば、? の後ろすべてが無視され、式全体の値が nil になる。そうでなければ、オプショナル値が解かれ、? の後ろのすべてにおいて解かれた値が用いられる。どちらの場合も、式全体の値がオプショナル値である。


let optionalSquare: Square? = Square( sideLength: 2.5, name: "optional square" )
let sideLength = optionalSquare?.sideLength

列挙型と構造体

列挙型を作るには enum を使う。クラスや他のすべての名前付き型と同様に、列挙型もそれに関連したメソッドを持てる。


enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String( self.rawValue )
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.rawValue

この例では、列挙型の生の値の型は Int であるから、最初の生の値をを指定さえすればよい。残りの生の値は順番に割り当てられる。生の値の型は文字列型も浮動小数点型も使える。列挙型のメンバーの生の値にアクセスする場合は rawValue プロパティを使う。生の値から列挙型のインスタンスを作る場合は init?(rawValue:) イニシャライザを使う。


if let convertedRank = Rank( rawValue: 3) {
lewt threeDescription - convertedRank.simpleDescription()
}

列挙型のメンバーの値は実際にその値であり、単に生の値の別の書き方というわけではない。実際、もし意味のある生の値が無い場合は、付ける必要も無い。


enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()

構造体を作るには struct を使う。構造体は、メソッドやイニシャライザも含めて、クラスと多くの同じ動作をサポートする。最も重要な違いの一つは、コード内で構造体が渡される時には常にコピーされるのに対し、クラスは参照が渡されるということである。


struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \( rank.simpleDescription() ) of \( suit.simpleDescription() )"
}
}
let threeOfSpades = Card( rank: .Three, suit: .Spades )
let threeOfSpadesDescription = threeOfSpaces.simpleDescription()

列挙型のメンバーのインスタンスは、そのインスタンスに関連付けられた値を持つことができる。同じ列挙型の複数インスタンスがそれぞれのインスタンスに関連付けられたことなる値を持つこともできる。値は、インスタンスを作るときに設定する。関連付けられた値と生の値は違うものである。列挙型のメンバーの生の値はすべてのインスタンスを通して同じであり、列挙型を定義するときに決められる。

以下の例参照。


enum ServerResponse {
case Result( String, String )
case Error( String )
}

let success = ServerResponse.Result( "午前6時", "午後8時9分" )
let failure = ServerResponse.Error( "チーズを切らした" )

switch success {
case let .Result( sunrise, sunset ):
let serverResponse = "日の出は \( sunrise ) で日の入りは \( sunset )。"
case let .Error( error ):
let serverResponse = "失敗...( error )"
}

スイッチケースに対する値マッチングの一部として ServerResponse の値が日の出と日の入りの時刻にどのように展開されるかに注目。

プロトコルとエクステンション

プロトコルを宣言するには protocol を用いる。


protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}

クラス、列挙型、構造体はすべてプロトコルに適合する。


class SimpleClass: ExampleProtocol {
var simpleDescription: String = "とても短いクラス。"
func adjust() {
simpleDescription = "100% アジャストした。"
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription

struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "シンプルな構造体"
mutating func adjust() {
simpleDescription += " (アジャスト済み)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

クラスの場合は mutating が不要だが構造体の場合は必要なことに注目。クラスではメソッドは常にクラスを変更可能だけれども構造体はそうではないからというのがその理由。

新しいメソッドや計算したプロパティのような機能追加をすでに存在する型に行う場合は、extension を用いる。プロトコル準拠を型に追加するにもエクステンションを使う。ライブラリやフレームワークからインポートした型にもエクステンションは使える。


extension Int: ExampleProtocol {
var simpleDescription: String {
return "数字 \( self )"
}
mutating func adjust() {
self += 42
}
}
7.simpleDescription

プロトコル名は、他のどんな名前付き型と同じように使える。例えば、型はみんな異なるけれども、みんな同じ単一のプロトコルに準拠する、というような場合に使える。プロトコル型の値を扱う場合、プロトコル定義以外のメソッドは利用できない。


let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty ←コメントを外すとエラー。

protocolValueSimpleClass のランタイム型だとしても、コンパイラはこれを ExampleProtocol の与えられた型として扱う。つまり間違えてこのプロトコル準拠に加えてクラスが実装するメソッドやプロパティにアクセスすることはできない。

ジェネリック

ジェネリックな関数や型を作るには名前を <>かっこで囲んで書く。


func repeat< Item > ( item: Item, times: Int ) -> [ Item ] {
var result = [ Item ] ()
for i in 0..<times {
result.append( item )
}
return result
}
repeat( "knock", 4 )

ジェネリックな形の関数やメソッドも、クラス、列挙型、構造体と同様に作ることができる。


// Swift 標準ライブラリのオプショナル型の再実装

enum OptionalValue<T> {
case None
case Some( T )
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some( 100 )

要求仕様のリストを指定するには、where を型名の後に書く。要求仕様とは、例えばプロトコルに準拠したり、2つの型を同じであるように要求したり、クラスが特定のスーパークラスを持つように要求するとか、そういうことである。


func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> ( lhs: T, rhs: U ) -> Bool {
for lhtItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements( [ 1, 2, 3 ], [ 3 ] )

単純な場合は、where を省略し、単にコロンに続けてプロトコルやクラス名を書く。<T: Equatable><T whereT: Equatable> と同じである。

(終わり)