はてな教科書の「プログラミング言語 Swift」を読んでます 1
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
のんびり読んでいきます。
序文を読んで
LLVM と Clang はその後の Apple プラットフォームにおける標準的なコンパイラの地位を占め、また OSS のコンパイラとして多くのプロジェクトに採用されている。
web系のソフトウェアエンジニアなので、OSSといっても、DLするコードだけGitHubとかホスティングサーバにあって、コンパイルはDLしてから自分のIDEであったりサーバであったり、という雰囲気だったので、そういえば、OSSはライブラリだけではないのだったという感じでした。
Playground に REPL など
REPLって聞いたことがあるのだけれどなんだっけ、と思ったら対話型評価環境のことでした...。
Rubyでいうと、irb
。PlayGroundにSwiftのREPLがあるそうで、iOSのプロジェクト*1のルートディレクトリあたりで、swift
と入力すると
$ swift Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.30). Type :help for assistance. 1>
のような表示がでたあと対話モードになりました。
これに気づいたので残りの章は入力しながら試すことにしました。
参考:
http://qiita.com/dll7/items/206d5bf0cb72942b3681
また、まだアップデートが活発だそうですが、細かいことはおいおい覚えます。
Swift の言語仕様を読んで
Constants and variables
// letはval(Kotlin), final修飾子のついた定数(Java) 6> let name = "Steve" name: String = "Steve" 7> name = "John" repl.swift:7:6: error: cannot assign to value: 'name' is a 'let' constant name = "John" ~~~~ ^ repl.swift:1:1: note: change 'let' to 'var' to make it mutable let name = "Steve" ^~~ var
// varは再代入可能な定数 7> var age = 56 age: Int = 56 8> age = 20 9> print(age) 20 // 型の定義, 型推論周りはKotlinと同じ 10> var age: Int = 56
Literal
Swiftのリテラルは
- 数値
- 真偽値
- 文字列
- nil
などがある。
数値
記述方法が多彩で、色のコードや大きな計算用の数値が読みやすくできそうですね。
let decimal = 21 let binary = 0b10101 // 二進数 let octal = 0o25 // 八進数 let hexadecimal = 0x15 // 十六進数 let decimal = 1.618 let exponent = 161.8e-2 // 常用対数
Optional
型を宣言するときに、その型かnilが入っていいよ、と宣言するのに使う型。
nilは正確にはOptional.NONE
という値になるそうです。
OptionalはKotlinでいうNullableに近いです。
var phoneNumber: Optional<String> = nil var phoneNumber: String? = nil
nilが入っていたら実行する、系のコードを一通り書いてみます。
12> var testString: String? = "test" testString: String? = "test" 13> if testString != nil { 14. print("testString is " + testString) 15. } repl.swift:14:30: error: value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'? print("testString is " + testString) // ()で包む必要がありました... ^ ! 13> var testString: String? = "test" testString: String? = "test" 14> if testString != nil { 15. print("testString is \(testString)") 16. } testString is Optional("test") 14> if testString != nil { 15. print("testString is \(testString)") 16. } testString is Optional("test") 17> testString = nil 18> if testString != nil { 19. print("testString is \(testString)") 20. } 21> // 実行されない 21> if testString != nil { 22. print("testString is \(testString!)") 23. } // 実行されない 24> print("testString is \(testString!)") fatal error: unexpectedly found nil while unwrapping an Optional value Execution interrupted. Enter code to recover and continue. Enter LLDB commands to investigate (type :help for assistance.)
Optional!
はNullable!!
と同じように、Optionalの値がnilだったら例外を発生します。
25> testString = "exist" 26> if let assigned = testString { 27. print("The testString is existing \(assigned)") 28. } The testString is existing exist // ブロックの外ではif文で代入した変数は利用できない 32> print(assigned) repl.swift:32:7: error: use of unresolved identifier 'assigned' print(assigned) ^~~~~~~~
32> if var assigned = testString { 33. print("The testString is existing \(assigned)") 34. assigned = "reassign" 35. print("\(assigned)") 36. } The testString is existing exist reassign // letだとブロックの中で再代入できない 37> if let assigned = testString { 38. print("The testString is existing \(assigned)") 39. assigned = "reassign" 40. print("\(assigned)") 41. } repl.swift:39:14: error: cannot assign to value: 'assigned' is a 'let' constant assigned = "reassign" ~~~~~~~~ ^
nilが代入された時点でぬるぽを発生させたい場合は、?
の代わりに!
を利用してImplicitlyUnwrappedOptional
型で宣言する。
Tuple
37> let steve = ("Steve Jobs", 56) steve: (String, Int) = { 0 = "Steve Jobs" 1 = 56 } // このへんの記法、rubyでメソッドの返り値が配列の場合の記法と似ていて(下記) // まだ右辺がセットの値の組み合わせとして宣言されている分、 // こっちのほうがわかりやすいかも...? という気持ち 38> let (name, age) = steve name: String = "Steve Jobs" age: Int = 56 39> print(steve.0) Steve Jobs 40> print(name) Steve Jobs 41> print(age) 56
Rubyのメソッドの返り値が配列の場合の記法. Rails読んでるとたまに出会ったり...。
irb(main):001:0> def return_arr irb(main):002:1> [1, "a", nil] irb(main):003:1> end => :return_arr irb(main):004:0> num, str, null_var = return_arr => [1, "a", nil] irb(main):005:0> num => 1 irb(main):006:0> str => "a" irb(main):007:0> null_var => nil
Collection types
現在の Swift には Array, Dictionary, Set の3つのビルトインされたコレクション型がある。
それぞれ let で宣言されているとき、要素を変更することはできない。変更したい場合は var を使う。
48> let fishes = ["Mackerel", "Saury", "Sardine"] fishes: [String] = 3 values { [0] = "Mackerel" [1] = "Saury" [2] = "Sardine" } 49> fishes[0] = "Squale" repl.swift:49:11: error: cannot assign through subscript: 'fishes' is a 'let' constant fishes[0] = "Squale" ~~~~~~ ^ repl.swift:48:1: note: change 'let' to 'var' to make it mutable let fishes = ["Mackerel", "Saury", "Sardine"] ^~~
リテラルでは上記の通り変更できないみたいですが、これ、リテラルでない場合はどうなのでしょう、とちらっと思ったり、思わなかったりしました。
DictonaryがRubyでいうHashみたいですね。
49> let firstDictonary = [ 50. "Attest": 6, 51. "Basic" : 5, 52. "Core" : 4 53. ] firstDictonary: [String : Int] = 3 key/value pairs { [0] = { key = "Basic" value = 5 } [1] = { key = "Core" value = 4 } [2] = { key = "Attest" value = 6 } } 54> first Available completions: (τ_0_0): τ_0_10? firstDictonary: [String : Int] 54> firstDictonary["Basic"] $R3: Int? = 5
演算子を読んで
インクリメント、デクリメントが削除される予定があること、三項演算子があること、nil 結合演算子を使って、
let someValue = optionalInt(optionalIntがnilでない場合採用) ?? 0(optionalIntがnilの場合採用)
というふうにかけること、範囲演算子の書き方(... や ..<
)などが特徴的だな、と思いました。
Control flowを読んで
- if文の条件文に渡す式は真偽値を返させる
- switch/case派(when派ではない)
- 上から順に基本的にマッチしたcaseの処理以外は行われない
- 下の条件にもマッチさせたいときは
fallthrough
を使う - defaultが使えるが、全ての条件について記述する必要がある
switch文がとてもいい感じだなと思いました。
let theNumber: UInt = 42 switch theNumber { case 0..<10: print("Single digit") case 10..<100: print("Double digits") case 100..<1000: print("Triple digits") default: print("Very large") }
caseに合致するかがパターンマッチで判断される、というのがRubyに近いなと思いました。
また、Optional型がnilかどうかでも判定ができるようです。
55> let pair: (String?, String?) = ("Steve", "Bill") pair: (String?, String?) = { 0 = "Steve" 1 = "Bill" } 56> switch pair { 57. case let (a?, b?): 58. print("\(a) and \(b)") 59. case let (a?, _): 60. print(a) 61. case let (_, b?): 62. print(b) 63. case (_, _): 64. print("No man") 65. } Steve and Bill
明日に続きます。
*1:XCode7.3.1で作成