はてな教科書の「プログラミング言語 Swift」を読んでます 6
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
のんびり読んでいきます。もうちょい!
Casting
isでインスタンスの型を確認.
84> class Cat: Animal { 85. // 86. // A'(A をオーバーライド。ここに required 修飾子がないと、サブクラス PersianCat に、このイニシャライザのオーバーライドを強制できない) 87. // 88. required init() { 89. super.init() 90. } 91. } 92> class PersianCat: Cat {} 93> var persianCat = Per Available completions: PermutationGenerator PersianCat 93> var persianCat = PersianCat() persianCat: PersianCat = { __lldb_expr_47.Cat = { __lldb_expr_41.Animal = { name = "unknown" } } } 94> persianCat is Cat $R8: Bool = true
as
でキャストだが、スーパークラスにキャストする場合は、 as
, サブクラスにキャストする場合は、as?(Optionalで失敗したらnil)
かas!(キャスト失敗でランタイムエラー)
になります。
95> persianCat as Cat $R9: PersianCat = { __lldb_expr_47.Cat = { __lldb_expr_41.Animal = { name = "unknown" } } } 96> var cat = Cat() cat: Cat = { __lldb_expr_41.Animal = { name = "unknown" } } 97> cat as? PersianCat $R10: PersianCat? = nil 98> cat as! PersianCat Could not cast value of type 'Cat' (0x101336ab8) to 'PersianCat' (0x101336fe8). Execution interrupted. Enter code to recover and continue. Enter LLDB commands to investigate (type :help for assistance.)
どちらかというと、キャストに失敗したらelseみたいな例文が自信ないです...。
if let swift = source as? SwiftFile { compiled.append(swift.compile()) } else { compiled.append(source) }
128> if cat as? PersianCat { 129. print("persian") 130. } repl.swift:128:8: error: optional type 'PersianCat?' cannot be used as a boolean; test for '!= nil' instead if cat as? PersianCat { ^ (( ) != nil) 128> if let persia = cat as? PersianCat { 129. print("persian") 130. }
letなどブロックの中で使う変数の定義が条件式に入った場合のif文がよくわからないみたいなので気をつけてみようと思います。
Protocol
いわゆるインタフェース。
- プロパティ
- メソッド
- イニシャライザ
- subscript*1
の宣言ができます。
また、メソッドは、 { get }
, { get, set }
で可変かを指定できます。
また、Protocol同士も継承できます。
1> protocol Man { 2. var firstName: String { get } 3. var lastName: String { get } 4. init(firstName: String, lastName: String) 5. func printFullName() 6. } 7> struct Japanese : Man { 8. var firstName: String 9. var lastName: String 10. init(firstName: String, lastName: String) { 11. self.firstName = firstName 12. self.lastName = lastName 13. } 14. func printFullName() { 15. print("\(firstName)\(lastName)") 16. } 17. } 18> struct American : Man { 19. var firstName: String 20. var lastName: String 21. init(firstName: String, lastName: String) { 22. self.firstName = firstName 23. self.lastName = lastName 24. } 25. func printFullName() { 26. print("\(lastName) \(firstName)") 27. } 28. } 29> var Taro = Japanese(firstName: "Yoshida", lastName: "Taro") Taro: Japanese = { firstName = "Yoshida" lastName = "Taro" } 30> var Ken = American(firstName: "Yoshida", lastName: "Ken") Ken: American = { firstName = "Yoshida" lastName = "Ken" } 31> Taro.printFullName() YoshidaTaro 32> Ken.printFullName() Ken Yoshida 33> struct Arian : Man { 34. var firstName: String { set {} } 35. 36. init(firstName: String, lastName: String) { 37. self.firstName = firstName 38. self.lastName = lastName 39. } 40. func printFullName() { 41. print("\(lastName) \(firstName)") 42. } 43. } repl.swift:34:29: error: variable with a setter must also have a getter var firstName: String { set {} } ^
Protocolは複数継承させることができますが、複数の protocol に適合していることを protocol<SomeProtocol, AnotherProtocol>
と表現できるそうです。
33> Taro as? protocol<Man> $R0: Man? = (payload_data_0 = 0x0000000100509980 -> 0x00000001004fdde0 , payload_data_1 = 0x0000000000000000, payload_data_2 = 0x0000000000000000, instance_type = 0x00000001004f1218 nominal type descriptor for __lldb_expr_6.Japanese + 72, protocol_witness_0 = 0x00000001004f1110 protocol witness table for __lldb_expr_6.Japanese : __lldb_expr_4.Man in __lldb_expr_6) { payload_data_0 = 0x0000000100509980 -> 0x00000001004fdde0 payload_data_1 = 0x0000000000000000 payload_data_2 = 0x0000000000000000 instance_type = 0x00000001004f1218 nominal type descriptor for __lldb_expr_6.Japanese + 72 protocol_witness_0 = 0x00000001004f1110 protocol witness table for __lldb_expr_6.Japanese : __lldb_expr_4.Man in __lldb_expr_6 } 34> protocol Animal {} 35> Taro as? protocol<Man, Animal> $R1: protocol<Animal, Man>? = nil
Extension
メタプロらしいものです。
computed プロパティやメソッド、イニシャライザや subscript を追加できますが、storedプロパティは追加できません。
36> extension Int { 37. var hex: String { 38. return String(self, radix: 16) 39. } 40. } 41> 245.hex $R2: String = "f5"
また、extension は protocol も拡張でき、Protocol Extensions
といいます。
エラー処理
- 例外を発生するメソッドに
throws
をつける - 例外を投げる時は、
throw
- 例外は、
ErrorType
を継承した自分のクラスで定義できる - エラーを投げる関数の前に
try
をつけて、その関数をdo { } catch ErrorType { } ...
ブロックで囲む- 実際にエラーが発生しないことがわかっている場合は
try!
にしてエラーハンドリングしないことを明示できる(ただし実際に発生したらランタイムエラーになる) try?
にすると返り値がオプショナルになって、例外が発生した時はnilが返る- キャッチされなかったエラーはそのブロックの呼び出し元に伝播していきます
- 実際にエラーが発生しないことがわかっている場合は
- エラーを throws するクロージャの案件はおかわりで...
42> enum SomeError : ErrorType { 43. case Empty 44. case Numeric 45. } 46> func throwError(str: String) throws -> String { 47. if str.isEmpty { 48. throw SomeError.Empty 49. } 50. if let num = Int(str) { 51. throw SomeError.Numeric 52. } 53. return str 54. } 55> do { 56. let res = try throwError("") 57. print(res) 58. } catch SomeError.Empty { 59. print("Empty") 60. } catch SomeError.Numeric { 61. print("Numeric") 62. } Empty 63> do { 64. let res = try throwError("123") 65. print(res) 66. } catch SomeError.Empty { 67. print("Empty") 68. } catch SomeError.Numeric { 69. print("Numeric") 70. } Numeric 71> do { 72. let res = try throwError("abc") 73. print(res) 74. } catch SomeError.Empty { 75. print("Empty") 76. } catch SomeError.Numeric { 77. print("Numeric") 78. } abc
defer
関数の最後に必ず実行したい処理がある場合、defer 文を利用することができます。
79> func deferTest(str: String) { 80. defer { 81. print(str) 82. } 83. print(str + str + str) 84. } 85> deferTest("ABCD!") ABCD!ABCD!ABCD! ABCD! // 途中でreturnする場合...? 86> func deferTest2(str: String) { 87. defer { 88. print(str) 89. } 90. return 91. print(str + str + str) 92. } 93> deferTest2("ABCD!") ABCD!ABCD!ABCD! ABCD! // 途中で例外を投げる場合 94> func deferTest2(str: String) throws { 95. defer { 96. print(str) 97. } 98. throw SomeError.Empty 99. print(str + str + str) 100. } 101> deferTest2("ABCD!") ABCD! warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available. 102>
*1:ArrayやDictionaryのように[]の記法でクラスに値を変えさせるあれ