Slide 1

Slide 1 text

Essential Scala 第2章 式、型、値 2018.6.27 Takuya Tsuchida (@takuya0301)

Slide 2

Slide 2 text

第2章 式、型、値 2.1 最初のプログラム 2.2 オブジェクトとの相互作用 2.3 リテラルオブジェクト 2.4 オブジェクトリテラル 2.5 メソッドの書き方 2.6 複合式 2.7 まとめ 2

Slide 3

Slide 3 text

第2章 式、型、値 本章では Scala プログラムの基本的な構成要素である式、型、値について見ていきま す。それらのコンセプトを理解することが Scala プログラムがどう動くかというメンタルモ デルを形成するために重要です。 3

Slide 4

Slide 4 text

2.1 最初のプログラム Scala コンソールでは評価結果の型と値が表示されます。 "Hello world!" // res: String = Hello world! Scala のコードは左から右へ評価されます。 "Hello world!".toUpperCase // res: String = HELLO WORLD! 4

Slide 5

Slide 5 text

5

Slide 6

Slide 6 text

2.1.1 コンパイル時と実行時 コンパイル時には文法と型が検証されます。 toUpperCase."Hello world!" // error: identifier expected but string literal found. // toUpperCase."Hello world!" // 2.toUpperCase // error: value toUpperCase is not a member of Int // 2.toUpperCase // 6

Slide 7

Slide 7 text

2.1.1 コンパイル時と実行時 実行時にエラーが発生することもあります。 2/0 // java.lang.ArithmeticException: / by zero 7

Slide 8

Slide 8 text

8

Slide 9

Slide 9 text

2.1.2 式、型、値 式はプログラムテキストでコンパイル時に存在しています。プログラムテキストの構成要 素として定義や文も存在します。 型は、値が一貫性をもって解釈されるようにプログラム記述を制約するもので、コンパイ ル時に存在しています。型消去によって実行時には存在しません。 値はメモリに保存された情報で実行時に存在しています。Scala の値はすべてオブジェ クトです。 9

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

2.1.3 キーポイント:最初のプログラム Scala のメンタルモデルにおいて式、型、値が基本的な構成要素です。 式はプログラムの部品で値に評価されます。式は型を持ちます。 型はプログラム上の制限を表現し、コンパイル時にチェックされます。 値はメモリ上に存在し、実行しているプログラムが操作する対象です。Scala の値はす べてオブジェクトです。 11

Slide 12

Slide 12 text

2.2 オブジェクトとの相互作用 12 前節では Scala プログラムの基本的な構成要素である式、型、値を見ました。また、す べての値はオブジェクトであることも学びました。本章ではオブジェクトとオブジェクトとの 相互作用について学びます。

Slide 13

Slide 13 text

2.2.1 オブジェクト オブジェクトはデータとそのデータに対する操作の組み合わせのことです。 操作をメソッドと呼びます。 データはフィールドに保存されます。 13

Slide 14

Slide 14 text

2.2.2 メソッド呼び出し メソッドを呼び出すことでオブジェクトを作用させます。* "Hello world!".toUpperCase // res: String = HELLO WORLD! パラメーター(引数)を受け取れるメソッドもあります。 "abcdef".take(3) // res: String = abc 14 * オブジェクトを作用させる別の方法としてパターンマッチングがあります。

Slide 15

Slide 15 text

15

Slide 16

Slide 16 text

ノート:メソッド呼び出し文法 anExpression.methodName(param1, ...) anExpression.methodName ● anExpression はオブジェクトに評価される式 ● methodName はメソッドの名前 ● param1, ... はメソッドの引数として評価される1つ以上の式 16

Slide 17

Slide 17 text

17 2.2.3 演算子 Scala のすべての値はオブジェクトなので、プリミティブ型*に対してもメソッドが呼び出せ ます。 123.toShort // this is how we define a `Short` in Scala // res: Short = 123 Scala では演算子もメソッドです。Scala のメソッドはシンボルによる名前を使用できま す。 43 - 3 + 2 // res: Int = 42 43.-(3).+(2) // res: Int = 42 * Java のプリミティブ型にマッピングされる Int や Boolean などです。

Slide 18

Slide 18 text

ノート:中置演算子記法 a.b(c) と記述されるすべての Scala の式は a b c と記述できる。 a b c d e は a.b(c).d(e) と等価である。 18

Slide 19

Slide 19 text

19 2.2.3 演算子 すべての1引数メソッドは中置記法にできます。 "the quick brown fox" split " " // res: Array[String] = Array(the, quick, brown, fox) 前置記法、後置記法、右結合、代入演算子という記法もありますが中置記法に比べると 一般的ではありません。 Scala における演算子の優先順位*はメソッドの名前から推論されます。 * https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations

Slide 20

Slide 20 text

20

Slide 21

Slide 21 text

2.2.4 キーポイント:オブジェクトとの相互作用 Scala の値はすべてオブジェクトです。メソッドを呼び出すことでオブジェクトを作用させ ます。 Scala は数少ない演算子しか持たず、ほとんどすべてがメソッド呼び出しです。中置演 算子記法のような文法変換によってシンプルかつ読みやすいコードを維持しています。 21

Slide 22

Slide 22 text

2.3 リテラルオブジェクト 22 すでにいくつかの Scala の基本型を説明しました。本節では Scala の全リテラル式を網 羅することでその知識を完全なものにします。リテラル式はそれ自身が表す固定値を表 現します。 42 // res: Int = 42 リテラルと評価された値を混同しないでください。リテラル式はプログラムを実行する前 のプログラムテキストにおける表現で、値はプログラムを実行した後のメモリ上における 表現です。

Slide 23

Slide 23 text

2.3.1 数値 数値は Java に存在する同じ型を共有していて、32ビット整数の Int、64ビット浮動小数 点数の Double、32ビット浮動小数点数の Float、64ビット浮動小数点数の Double が あります。 42 // res: Int = 42 42.0 // res: Double = 42.0 42.0f // res: Float = 42.0 42L // res: Long = 42 23

Slide 24

Slide 24 text

24

Slide 25

Slide 25 text

2.3.2 真偽値 真偽値は Java と同じで true か false です。 true // res: Boolean = true false // res: Boolean = false 25

Slide 26

Slide 26 text

26

Slide 27

Slide 27 text

2.3.3 文字 文字は16ビットの Unicode 値で、シングルクォートで囲まれた単一の文字で表現しま す。 'a' // res: Char = a 27

Slide 28

Slide 28 text

28

Slide 29

Slide 29 text

2.3.4 文字列 文字列は Java と同じで、ダブルクォートで囲まれた文字列で表現します。 "this is a string" // res: String = this is a string "the\nusual\tescape characters apply" // res: String = // the // usual escape characters apply 29

Slide 30

Slide 30 text

30

Slide 31

Slide 31 text

2.3.5 Null Null は Java と同じですが、Java ほど頻繁には利用されません。Scala の null は Null 型を持ちます。 31

Slide 32

Slide 32 text

32

Slide 33

Slide 33 text

2.3.6 Unit Unit は Java の void と同じで、() で表現します。Unit は、標準出力に使用される println など、興味深い値に評価されない式の結果で使用されます。 多くの Scala の文法的構成要素は式で型と値を持ちます。有用な値を生成しない式の ためのプレースホルダーとして Unit は必要になります。 33

Slide 34

Slide 34 text

34

Slide 35

Slide 35 text

2.3.7 キーポイント:リテラルオブジェクト 本節では基本データ型に評価されるリテラル式を見ました。基本型のほとんどは Unit を 除いて Java と同じです。 すべてのリテラル式は型を持ち値に評価されます。 35

Slide 36

Slide 36 text

2.4 オブジェクトリテラル 36 本節ではオブジェクトリテラルを使用して独自設計のオブジェクト生成します。オブジェク トリテラルを記述するときは、式ではなく宣言を使用します。 空のオブジェクトを宣言します。これは値に評価されませんが、Test という名前に「空の オブジェクト」という値が束縛されます。 object Test {} Test // res: Test.type = Test$@2c8c42c Test を評価すると Test.type という型に評価されます。Test.type は、このオブジェクト のためにつくられた新しい型でシングルトン型と呼ばれます。

Slide 37

Slide 37 text

37

Slide 38

Slide 38 text

ノート:オブジェクト宣言記法 object name { declarationOrExpression ... } ● name はオブジェクトの名前 ● declarationOrExpression は宣言や式(省略可能) 38

Slide 39

Slide 39 text

2.4.1 メソッド オブジェクトはメソッドを通して作用されます。 object Test2 { def name: String = "Probably the best object ever" } Test2.name // res: String = Probably the best object ever 39

Slide 40

Slide 40 text

2.4.1 メソッド これはより複雑なメソッドの例です。 object Test3 { def hello(name: String) = "Hello " + name } Test3.hello("Noel") // res: String = Hello Noel 40

Slide 41

Slide 41 text

41

Slide 42

Slide 42 text

ノート:メソッド宣言記法 def name(parameter: type, ...): resultType = bodyExpression or def name: resultType = bodyExpression ● name はメソッドの名前 ● parameter は1つ以上の引数の名前(省略可能) ● type はメソッドの引数の型 ● resultType はメソッドの結果の型(省略可能) ● bodyExpression はメソッドが呼び出されたときに評価される式 42

Slide 43

Slide 43 text

ノート:return は暗黙的 メソッドの戻り値は本体を評価することによって決定される。Java でやるように return を 書く必要はない。 43 * メソッドの戻り値はメソッド本体の式の評価結果になります。Java のように return を記述する必要はありません。

Slide 44

Slide 44 text

2.4.2 フィールド オブジェクトはフィールドにほかのオブジェクトを持てます。 object Test4 { val name = "Noel" def hello(other: String): String = name + " says hi to " + other } Test4.hello("Dave") // res: String = Noel says hi to Dave 44

Slide 45

Slide 45 text

2.4.2 フィールド val で不変フィールドを定義できます。不変フィールドは名前に束縛された値を変更する ことができません。var で可変フィールドを定義できます。可変フィールドは名前に束縛さ れた値を変更できます。 常に var より val を選びましょう。Scala プログラマーは不変フィールドを使用することを 好みます。本書の大部分では var を避けているので、Scala プログラミングをするときは 真似してみてください。 45

Slide 46

Slide 46 text

46

Slide 47

Slide 47 text

ノート:フィールド宣言記法 val name: type = valueExpression or var name: type = valueExpression ● name はフィールドの名前 ● type はフィールドの型(省略可能) ● valueExpression はオブジェクトに評価されて名前に束縛される 47

Slide 48

Slide 48 text

2.4.3 メソッド対フィールド フィールドは値に名前を与え、メソッドは値を生成する計算に名前を与えます。 object Test7 { val simpleField = { println("Evaluating simpleField") 42 } def noParameterMethod = { println("Evaluating noParameterMethod") 42 } } 48

Slide 49

Slide 49 text

2.4.3 メソッド対フィールド オブジェクトは遅延ローディングされるため、参照されるまで評価されません。 Test7 // Evaluating simpleField // res: Test7.type = Test7$@b22e8c9 フィールドの式はただ1回だけ実行され、その結果がフィールドに保存されます。 Test7.simpleField // res: Int = 42 Test7.simpleField // res: Int = 42 49

Slide 50

Slide 50 text

2.4.3 メソッド対フィールド メソッドの式はメソッドが呼び出されるたびに実行されます。 Test7.noParameterMethod // Evaluating noParameterMethod // res: Int = 42 Test7.noParameterMethod // Evaluating noParameterMethod // res: Int = 42 50

Slide 51

Slide 51 text

51

Slide 52

Slide 52 text

2.4.4 キーポイント:オブジェクトリテラル 本節では式を参照するメソッドとフィールドが与えられた独自のオブジェクトを生成しまし た。 オブジェクト・メソッド・フィールドを宣言する文法を見てきました。 それらすべては名前に値を束縛します。宣言は式と異なり、値として評価されず、型も持 ちません。 また、メソッドとフィールドには、フィールドはオブジェクトに保存された値を参照します が、メソッドは値を生成する計算を参照するという違いがあります。 52

Slide 53

Slide 53 text

2.5 メソッドの書き方 53 本書では文法を越えて Scala プログラムを構築する体系的な方法を与えることが主目 的のひとつです。 本節ではメソッドを構築するための体系的な方法を見ていきます。Scala についての経 験がある場合、方法のいくつかのステップを省略できるかもしれませんが、本書を読ん でいる間はこの方法を踏襲することを強く推奨します。 このアドバイスを具体的にするために前節の課題を例題として使用します。 例題:calc オブジェクトを square メソッドを持たせて定義してください。square メソッド は Double を引数とし、その入力を2乗します。

Slide 54

Slide 54 text

2.5.1 入力と出力を確認する メソッドにおける引数の型と結果の型を確認します。 例題の説明によると引数の型は Double です。結果の型も Double であると推測できま す。 54

Slide 55

Slide 55 text

2.5.2 テストケースを準備する 型はすべてのストーリーを語りません。Double から Double への関数はたくさんありま すが、2乗を実装しているものは一握りです。なので、メソッドの期待される振る舞いを描 き出すためにテストケースを準備します。 assert(square(2.0) == 4.0) assert(square(3.0) == 9.0) assert(square(-2.0) == 4.0) 55 * 本書では外部依存を避けるためにテストライブラリを使用しません。

Slide 56

Slide 56 text

56

Slide 57

Slide 57 text

57 2.5.3 宣言を書く 型とテストケースがあるのでメソッド宣言を書くことができます。未実装であるメソッドの 本体には Scala の機能である ??? を使用できます。 def square(in: Double): Double = ??? この宣言はこれまでのステップで集めた情報によって機械的にもたらされるべきです。

Slide 58

Slide 58 text

58

Slide 59

Slide 59 text

59 2.5.4 コードを実行する コンパイルとテストの失敗をチェックするためにコードを実行します。

Slide 60

Slide 60 text

60

Slide 61

Slide 61 text

2.5.5 本体を書く メソッドの本体を書く技法は2つあります。 1つ目は結果の型について考える技法です。例題の結果の型は Double です。どうやっ たら Double を生成できるでしょうか?リテラルを書くこともできますが、当然ながらこの ケースでは正しくありません。 2つ目は引数の型について考える技法です。例題の引数の型は Double です。Double を生成する必要性も確認済みです。入力から Double を生成するメソッドにどんなもの があるでしょうか?そのようなメソッドはたくさんあるので、ドメイン知識を活用し、呼ぶべ き正しい * メソッドを選択します。 def square(in: Double): Double = in * in 61

Slide 62

Slide 62 text

2.5.6 コードを再実行する コードを再実行してテストがすべてパスすることをチェックします。 62

Slide 63

Slide 63 text

63

Slide 64

Slide 64 text

ノート:メソッドの書き方についての手順 1. メソッドにおける入力と出力の型を確認する。 2. 与えられた入力例から期待されるメソッドの出力についてテストケースを記述する。 それらのケースを書くために assert 関数を利用する。 3. 下記のように本体に ??? を使用してメソッド宣言を記述する。 def name(parameter: type, ...): resultType = ??? 4. テストケースが失敗することをチェックするためにコードを実行する。 5. メソッドの本体を記述する。そのために下記のような2つの技法がある。 ● 結果の型について、それのインスタンスをどう作成できるか検討する。 ● 入力の型について、それをどう結果の型に変換できるか検討する。 6. コードを再実行し、テストケースをパスすることをチェックする。 64

Slide 65

Slide 65 text

2.6 複合式 65 本節では、より複雑なプログラムを書くために必要な2つの特別な式、条件式とブロック について見ていきます。

Slide 66

Slide 66 text

2.6.1 条件式 条件式はいくつかの条件にもとづいて式を選択することを可能にします。 if (1 < 2) "Yes" else "No" // res: String = Yes 選択されなかった式は評価されません。 if (1 < 2) println("Yes") else println("No") // Yes 66

Slide 67

Slide 67 text

67

Slide 68

Slide 68 text

ノート:条件式は式である Scala の if 文は Java と同じ文法を持つ。重要な違いは Scala の条件式は式であるの で型を持ち値を返す。 68

Slide 69

Slide 69 text

ノート:条件式記法 if(condition) trueExpression else falseExpression ● condition は Boolean 型の式 ● trueExpression は条件が true に評価されるときに評価される式 ● falseExpression は条件が false に評価されるときに評価される式 69

Slide 70

Slide 70 text

2.6.2 ブロック ブロックは一連の計算をまとめる式です。それらはセミコロンもしくは改行で区切られた 式を中括弧で囲むように書きます。 { 1; 2; 3 } // some warnings... // res41: Int = 3 70

Slide 71

Slide 71 text

2.6.2 ブロック ブロックは式を順に評価し、最後の式における値を返す式です。 ブロックを利用するひとつの理由として、最後の値を計算する前に副作用を発生させた いということがあります。 { println("This is a side-effect") println("This is a side-effect as well") 3 } // This is a side-effect // This is a side-effect as well // res: Int = 3 71

Slide 72

Slide 72 text

2.6.2 ブロック ブロックを利用するもうひとつの理由として、中間の結果に名前をつけたいということが あります。 def name: String = { val title = "Professor" val name = "Funkenstein" title + " " + name } name // res: String = Professor Funkenstein 72

Slide 73

Slide 73 text

73

Slide 74

Slide 74 text

ノート:ブロック式記法 { declarationOrExpression ... expression } ● declarationOrExpression は宣言か式(省略可能) ● expression はブロック式の型と値を決定する式 74

Slide 75

Slide 75 text

2.6.3 キーポイント:複合式 条件式は条件にもとづいて式を選択することを可能にします。条件式は式なので型を持 ちオブジェクトに評価されます。 if (condition) trueExpression else falseExpression ブロックは式と宣言を順に並べることを可能にし、副作用の発生と中間の結果への命名 で利用されます。最後の式がブロックの型と値になります。 { declarationOrExpression ... expression } 75

Slide 76

Slide 76 text

2.7 まとめ 76 下記のような Scala の基本について簡潔に紹介しました。 ● 値に評価される式 ● 値に名前を与える宣言 様々なオブジェクトのためにリテラルを書く方法、メソッド呼び出しや複合式で既存のも のから新しいオブジェクトを作る方法を見てきました。 また、メソッドとフィールドで構成される独自のオブジェクトを宣言することもできるように なりました。 次章ではオブジェクトを作成するためのテンプレートとしてクラスの宣言を見ていきます。 クラスはコードの再利用と類似するオブジェクトの共通型としての統一を可能にします。