前を向くために Part3

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

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

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章基本事項終わり)