リテラルと型の話 #__swift__

137 Views

December 20, 15

スライド概要

2015-12-20 に開催された『集まれ! Swift 好き!Swift 愛好会』で話した資料です。補足事項を少し追加してます。

※ Docswell での公開に移行する直前の Slideshare での閲覧数は 5,019 でした。

profile-image

正統派趣味人プログラマー。プログラミングとは幼馴染です。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Swift カジュアルプログラミング リテラルと型 の話 2015.12.20 @ 集まれ Swift 好き!Swift 愛好会 EZ-NET 熊⾕友宏 Swift 2.1.1 http://ez-net.jp/

2.

熊谷友宏 EZ-NET http://ez-net.jp/ @es̲kumagai iOS, OS X, Apple Watch アプリ CodePiece いつもの電卓 ソースコードを Twitter と Gist に同時投稿できる。 計算式も見える電卓アプリ。 watchOS 1 対応 音で再配達ゴッド EZ-NET IP Phone 簡単操作で 再配達の申し込み。 iPhone でひかり電話を使う。 自宅 LAN からの利用専用

3.

CodePiece for OS X 勉強会を楽しむアプリ ソースコードを Twitter と Gist に同時投稿できる 勉強会で知見をみんなと共有したい時とかに便利! できること #̲̲swift̲̲

4.

熊谷友宏 EZ-NET http://ez-net.jp/ @es̲kumagai 勉強会 横浜 iPhone 開発者勉強会 カジュアル Swift 勉強会 【 横浜・馬車道 】 #yidev 【 横浜・青葉台 】 #cswift わいわい・ゆるく、iPhone 開発者の みんなで楽しく過ごすのが目的の会 ゆるくみんなで Swift を語らえる場を 作りたくて始めた会 第22回を 2016-03-05 に開催予定 第4回を 2015-12-26 に開催

5.

熊谷友宏 EZ-NET http://ez-net.jp/ @es̲kumagai 書籍 / 登壇 Xcode 5 徹底解説 MOSA Xcode 5 の全機能を 徹底的に解説した本 OSX/iOS 系の歴史深い 有料会員制の勉強会 Xcode 7 でも役立つはず 法人会員も多数 紙版は絶版、電子書籍は販売中 秀和システム 10x-Eng.com で取扱予定

6.

混乱しがちな? リテラルの話

7.

リテラルの話 構成 1. リテラルの基礎を知り 2. リテラルの仕組みを把握して 3. リテラルの実際の動きを掌握する

8.

リテラル 概要

9.

リテラル 概要 ▶ コードで値を書くのに使う ▶ 具体的な内容を記述する "Swift" 2.1

10.

リテラル 種類 ▶ 整数リテラル … 3 ▶ 小数点数リテラル … 3.1 ▶ 真偽値リテラル … true, false ▶ 文字列リテラル … "STRING" ▶ nil リテラル … nil ▶ 配列リテラル … [ value, ... ] ▶ 辞書リテラル … [ key : value, ... ]

11.

【補足】リテラルと即値 リテラル【 Literal 】 ▶ 書いたまんま、というのを表す言葉 ▶ 高級言語の用語で、コードに直接記載された値 即値【 Immediate 】 ▶ 直接的なものを表す言葉 ▶ アセンブラ用語で、コードに直接埋め込んだデータ 言葉が違うからリテラルを即値と訳すのは誤りとする説も ありますが、訳として間違いとも言えない気もします。

12.

リテラルを書く

13.

リテラルの書式 (1/7) 整数リテラル ▶ 2進数、8進数、10進数、16進数で表記可能 ▶ 各数字の後ろに自由に ̲ を挿入できる 200 0xc8 0o310 0b11001000 // 10 進数 // 16 進数 // 8 進数 // 2 進数 20_000_000 // _ は無視される

14.

リテラルの書式 (2/7) 小数点数リテラル ▶ 10進数、16進数で表記可能 ▶ 各数字の後ろに自由に ̲ を挿入できる 2.10 // 10進数 1.25e-4 0x15.8p3 // 10進数 … 1.25 × 10-4 // 16進数 … 0x15.8 × 23 1.001_001_e-8 // _ は無視される

15.

リテラルの書式 (3/7) 真偽値リテラル ▶ 真か偽かの2種類だけ true false // 真を表現 // 偽を表現

16.

リテラルの書式 (4/7) 文字列リテラル ▶ 引用符で括って文字列を表現 ▶ 特別な文字も挿入可能 "Swift" // Swift "\"Swift\"" "Header:\tText" "!\u{20DD}" // "Swift" // Header: Text // ! ⃝

17.

リテラルの書式 (5/7) nil リテラル ▶ 無 を表現 nil // 無

18.

リテラルの書式 (6/7) 配列リテラル ▶ 複数の要素を持つことを表現 ▶ 各要素は自由に指定 [ 1.5, val, "STR" ] [] // 3つの要素を持つ配列 // 何も要素を持たない配列

19.

リテラルの書式 (7/7) 辞書リテラル ▶ 複数の要素を持つことを表現 ▶ 各要素は キー と 値 の対で自由に指定 [ "A" : 10, "B" : 20 ] [:] // 2つの要素を持つ辞書 // 何も要素を持たない辞書

20.

リテラルを使う

21.

リテラルの使い方 コード内にリテラルを書く ▶ 変数に入れて使う let name = let version = "Swift" 2.1

22.

リテラルの大事なところ 基礎

23.

リテラルに 型 はない

24.

リテラルの大事なところ リテラル自体に型はない ▶ リテラルだけでは値はできない let value = nil Type of expression is ambiguous with more context

25.

リテラルを型に嵌める必要がある

26.

リテラルの大事なところ 型を明記して値にする ▶ リテラルが型の値に変換される ▶ 前後関係から適切な型が決定される let value = nil as Int? let value: Int? = nil

27.

でも、型を明記しないで リテラルを使えていたような? let name = "Swift" let version = 2.1

28.

リテラルの既定の型

29.

リテラルの大事なところ リテラルを型に嵌める ▶ リテラルは型を明示して値にする ▶ 明示されないときは 既定の型 とみなす // 整数リテラルが Double 型に決まる let value = 10 as Double Double 型 // 整数リテラルが Int 型とみなされる let value = 10 Int 型

30.

リテラルの大事なところ 型が明示されないときの既定の型 ▶ 整数リテラル … Int 型 ▶ 小数点数リテラル … Double 型 ▶ 真偽値リテラル … Bool 型 ▶ 文字列リテラル … String 型 ▶ nil リテラル … なし ▶ 配列リテラル … Array 型 ▶ 辞書リテラル … Dictionary 型

31.

リテラルの大事なところ 前後関係からも型が決まる ▶ 前後関係からも型が推論される ▶ たとえば、代入や計算 // Double 型の変数があるとき let value: Double = 10 // 整数リテラルが Double 型とみなされる let answer = value * 10 Double 型

32.

リテラルの大事なところ 前後関係からも型が決まる ▶ 前後関係からも型が推論される ▶ たとえば、関数の引数 // Double 型を受け取る関数があるとき func doSomething(value: Double) { } // 渡したリテラルが Double 型とみなされる doSomething( 10 ) Double 型

33.

【余談】配列リテラルからの型推論 型が既に決められている場合はそれに従う let array: [Int] = [10, 20, 30] 内容から [Double] 型と推論 let array = [3.01, 3.12, 3.23, 3.34] オブジェクト型は継承関係も考慮して推論 let array = [りんご(), みかん(), ぶどう()] [Int] 型 [Double] 型 [くだもの] 型 プロトコルの準拠性や継承関係では推論されない

34.

リテラルを型に嵌める仕組み 実践

35.

型がリテラルを引き受ける仕組み

36.

型がリテラルを引き受ける リテラルを受け入れられる型 ▶ 型がリテラルの受け入れを表明する ▶ 対応リテラルは LiteralConvertible で決定 // IntegerLiteralConvertible を表明していれば enum MyVariant : IntegerLiteralConvertible { } // 整数リテラルを受け入れられる let value: MyVariant = 10

37.

型がリテラルを引き受ける 型が責任を持って値を作る ▶ イニシャライザーでリテラルを受け取る ▶ 受け取った値を適切なデータに変換する enum MyVariant : IntegerLiteralConvertible { case IntegerValue(Int) case FloatingPointValue(Double) init(integerLiteral value: Int) { self = .IntegerValue(value) } }

38.

型がリテラルを引き受ける 受け入れ表明で使うプロトコル ▶ 整数リテラル … IntegerLiteralConvertible ▶ 小数点数リテラル … FloatLiteralConvertible ▶ 真偽値リテラル … BooleanLiteralConvertible ▶ 文字列リテラル … StringLiteralConvertible ▶ nil リテラル … NilLiteralConvertible ▶ 配列リテラル … ArrayLiteralConvertible ▶ 辞書リテラル … DictionaryLiteralConvertible

39.

【補足】IntegerLiteralConvertible 定義 protocol IntegerLiteralConvertible { typealias IntegerLiteralType init(integerLiteral value: IntegerLiteralType) } 整数リテラルを受け取るときに使うイニシャライザーが 規定されています。これに準拠した型は整数リテラルを 受け入れられる型になります。

40.

【補足】StringLiteralConvertible 定義 protocol StringLiteralConvertible : ExtendedGraphemeClusterLiteralConvertible { typealias StringLiteralType init(stringLiteral value: StringLiteralType) } protocol ExtendedGraphemeClusterLiteralConvertible : UnicodeScalarLiteralConvertible { typealias ExtendedGraphemeClusterLiteralType init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) } protocol UnicodeScalarLiteralConvertible { typealias UnicodeScalarLiteralType init(unicodeScalarLiteral value: UnicodeScalarLiteralType) } 文字列リテラルを受け取るときに使うイニシャライザーが 規定されています。複数のプロトコルを継承しています。 init(stringLiteral:) 以外の使われ方を教えてください !

41.

リテラルと型の関係

42.

リテラルと型の関係 おさらい ▶ 型がリテラルを引き受ける ▶ リテラル自体に型はない // リテラルは、いろんな型に染まる let value: Int = 10 let value: UInt64 = 10 let value: Double = 10 let value: NSNumber = 10

43.

リテラルと型の関係 関係性から見えてくること Q. nil は Optional 型? A. Optional 型が nil を 空として扱う

44.

リテラルと型の関係 関係性から読めてくること Q. true は Bool 型? A. A. Bool 型が true を真 として扱う NSNumber 型が真と扱っても良い

45.

リテラルと型の関係 リテラルの扱いは型の裁量で決まる ▶ リテラルをどう扱うかは型の責任 ▶ リテラルの意味を尊重することは重要 // 整数リテラルを 32 bit 整数 として扱う let number: Int32 = 100 // nil リテラルを 何もない として扱う let value: String? = nil // 配列リテラルを オプションセット として扱う let options: UIViewAutoresizing = [.FlexibleWidth, .FlexibleHeight]

46.

Q. 整数リテラルは Int 型?

47.

リテラルから受け取る値 たとえば … 型の内容が UInt64 で 表現されるとき リテラルが Int 型だと 表現しきれない

48.

リテラルから受け取る値 リテラルを 64 bit 符号なし整数で扱いたい ▶ 型の内容が UInt64 で表現されるとき ▶ リテラルが Int 型では表現しきれない struct UserID : IntegerLiteralConvertible { var value: UInt64 init(integerLiteral value: Int) { self.value = UInt64(value) } }

49.

💡 リテラルには型がない

50.

リテラルから受け取る値 リテラルを 64 bit 符号なし整数で受け取る ▶ リテラルは 任意の型で受け取れる ▶ ただし、互換性のあるものに限る struct UserID : IntegerLiteralConvertible { var value: UInt64 init(integerLiteral value: UInt64) { self.value = value } }

51.

リテラル変換で受け取る値 リテラルの値の範囲を絞れる ▶ 小さい型でも受け取れる ▶ 範囲を超えると ビルドタイム でエラー struct Word : IntegerLiteralConvertible { init(integerLiteral value: UInt8) { … } } let word1: Word = 255 let word2: Word = 300 Integer literal '300' overflows when stored into 'UInt8'

52.

【余談】IntegerLiteralType の互換性 定義 struct MyIntegerLiteral : ̲BuiltinIntegerLiteralConvertible { var value: Int8 init(̲builtinIntegerLiteral value: ̲MaxBuiltinIntegerType) { self.value = Int8(̲builtinIntegerLiteral: value) } } 使用 struct MyStruct : IntegerLiteralConvertible { init(integerLiteral value: MyIntegerLiteral) { } } このようにするとリテラルの値を自作の型で受け取れます。 ただし、ビルド時のオーバーフロー検出は行われません。

53.

リテラルの動きを捉える 演習

54.

1/5 リテラルから値を生成 する

55.

リテラルの動きを捉える リテラルから値を生成する ▶ リテラルに型を指定して値を作る ▶ 変換イニシャライザーが呼び出される enum MyVariant : IntegerLiteralConvertible { } // A. 型を明記した変数にリテラルを入れる方法 let value: MyVariant = 200 // B. リテラルに型を明記する方法 let value = 200 as MyVariant

56.

リテラルの動きを捉える リテラルから値を生成する リテラル 変換イニシャライザー 型を明示 型 値

57.

2/5 型を複数のリテラルに対応する

58.

リテラルの動きを捉える 型を複数のリテラルに対応する ▶ 複数のリテラルコンバーティブルに準拠 ▶ それぞれのリテラルを受容可能になる // 型が複数のリテラルを受け入れるときに enum MyVariant : IntegerLiteralConvertible, FloatLiteralConvertible { } // 対応するどのリテラルからも生成可能 let value1: MyVariant = 200 let value2: MyVariant = 150.8

59.

リテラルの動きを捉える 型を複数のリテラルに対応する 整数 リテラル 小数点数用の変換イニシャライザー 整数用の変換イニシャライザー 型を明示 型 値

60.

3/5 値をリテラルと比較 する

61.

リテラルの動きを捉える 値をリテラルと比較する ▶ リテラルと直接的に比較できる ▶ 型が比較可能なことが条件 enum MyVariant : IntegerLiteralConvertible, Equatable { } let value: MyVariant = 200 // リテラルと直接的に比較可能 if value == 300 { }

62.

リテラルの動きを捉える 値をリテラルと比較する 値 == リテラル 型を推論 型 変換イニシャライザー 同じ型での比較原則 値

63.

4/5 関数の引数にリテラルで渡す

64.

リテラルの動きを捉える 関数の引数にリテラルで渡す ▶ リテラルを直接引数に渡せる ▶ 目的の型の値へ暗黙的に変換される // 型を引数で受け取る関数に func calculate(value: MyVariant) { } // 対応するリテラルを直接的に渡せる calculate(120)

65.

リテラルの動きを捉える 関数の引数にリテラルで渡す 関数(value:型) リテラル 型を推論 型 変換イニシャライザー 値

66.

5/5 列挙型の Raw 値で自作の型を使う

67.

リテラルの動きを捉える 列挙型のRaw 値で自作の型を使う ▶ リテラル対応の型を Raw 値に使える ▶ 使えるリテラルは整数、小数、文字列のみ // 列挙子の値はリテラルで指定する enum Coefficient : MyVariant { case Treble = 3 case Halve = 0.5 } // Raw 値を MyVariant 型で取得できる Coefficient.Treble.rawValue

68.

リテラルの動きを捉える 列挙型のRaw 値で自作の型を使う 列挙型 列挙子A Raw 型 リテラル rawValue Raw 型 変換イニシャライザー 列挙子B リテラル Raw 値

69.

【補足】列挙型の Raw 値で使えるリテラル ▶ 整数リテラル ▶ 小数点数リテラル ▶ 文字列リテラル 複数種類のリテラルを受け入れられる型を Raw 型に指定すると Raw 値に複数のリテラルを混ぜて指定できるようになります。

70.

隠しリテラル ? おまけ

71.

カラーリテラル Color Literal

72.

カラーリテラル 概要 [#Color(colorLiteralRed: R, green: G, blue: B, alpha: A)#] import UIKit let color: UIColor = [#Color(colorLiteralRed: 0.6587, green: 1.0000, blue: 0.6987, alpha: 1.0000)#]

73.

カラーリテラル Literal Convertible protocol _ColorLiteralConvertible { init(colorLiteralRed: Float, green: Float, blue: Float, alpha: Float) } extension NSColor : _ColorLiteralConvertible { } extension UIColor : _ColorLiteralConvertible { }

74.

カラーリテラル Playground で使う 1. コード行に [#Color#] と書く 2. インラインに 箱 が描かれる 3. 箱をダブルクリックして カラーピッカー で選べる Playground

75.

カラーリテラル Playground での使用例 Playground

76.

カラーリテラル カラーパレットからの入力も可能 カーソル行へのドロップで入力 Playground

77.

カラーリテラル カラーパレットは Edit メニューから表示 Playground

78.

画像リテラル Image Literal

79.

画像リテラル 概要 [#Image(imageLiteral: PATH )#] import UIKit let image: UIImage = [#Image(imageLiteral: "Swift.png")#]

80.

画像リテラル Literal Convertible protocol _ImageLiteralConvertible { init(imageLiteral: String) } extension NSImage : _ImageLiteralConvertible { } extension UIImage : _ImageLiteralConvertible { }

81.

画像リテラル Playground で使う A. コード行に直接書く [#Image(imageLiteral: "Swift.png")#] OR B. コードに画像を直接ドロップする Playground

82.

画像リテラル Playground での使用例 Playground

83.

ファイルリテラル File Reference Literal

84.

ファイルリテラル 概要 [#FileReference(fileReferenceLiteral: PATH )#] import Foundation let path: NSURL = [#FileReference( fileReferenceLiteral: "main.mm")#]

85.

ファイルリテラル Literal Convertible protocol _FileReferenceLiteralConvertible { init(fileReferenceLiteral: String) } extension NSURL : _FileReferenceLiteralConvertible { }

86.

ファイルリテラル Playground で使う A. コード行に直接書く [#FileReference(fileReferenceLiteral: "main.mm")#] OR B. コードにファイルを直接ドロップする Playground

87.

ファイルリテラル Playground での使用例 Playground

88.

以上 型とリテラルの話

89.

リテラルと型の話 まとめ 1. リテラルを書く・リテラルを使う 2. リテラルの大事なところ ✓ リテラルに型はない ✓ リテラルを型に嵌める ✓ リテラルの既定の型 3. リテラルを型に嵌める仕組み ✓ 型がリテラルを受け入れる ✓ リテラルと型の関係 4. リテラルの動きを捉える 5. 隠しリテラル?