Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Essential Scala 第3章 オブジェクトとクラス / Essential Scala Chapter 3 Objects and Classes

Essential Scala 第3章 オブジェクトとクラス / Essential Scala Chapter 3 Objects and Classes

Takuya Tsuchida

July 18, 2018
Tweet

More Decks by Takuya Tsuchida

Other Decks in Programming

Transcript

  1. 3.1.1 クラス定義 これが Person クラスの定義です。 class Person { val firstName

    = "Noel" val lastName = "Welsh" def name = firstName + " " + lastName } オブジェクト宣言のようにクラス宣言は名前を束縛します。しかし、クラス名は式で利用 できません。クラスは値ではなく、違う名前空間に存在しています。 Person // error: not found: value Person // Person // ^
  2. 3.1.1 クラス定義 オブジェクトの型は Person です。new 呼び出しごとに、同じ型で別個のオブジェクトが 生成されます。 noel // res:

    Person = Person@3235186a val newNoel = new Person // newNoel: Person = Person@2792b987 val anotherNewNoel = new Person // anotherNewNoel: Person = Person@63ee4826
  3. 3.1.1 クラス定義 これで Person を引数とするメソッドを書くことができます。 object alien { def greet(p:

    Person) = "Greetings, " + p.firstName + " " + p.lastName } alien.greet(noel) // res: String = Greetings, Noel Welsh alien.greet(newNoel) // res: String = Greetings, Noel Welsh
  4. ノート:Java メモ Scala クラスは java.lang.Object のサブクラスであり、ほとんどのものは Java から Scala のそれと同じように使用できる。Person

    におけるデフォルトの出力の振る舞いは java.lang.Object で定義されている toString メソッドによるものである。 13
  5. 3.1.2 コンストラクター コンストラクターは新しいオブジェクトを生成するときに引数を渡すことを可能にします。 class Person(first: String, last: String) { val

    firstName = first val lastName = last def name = firstName + " " + lastName } val dave = new Person("Dave", "Gurnell") // dave: Person = Person@3ed12df7 dave.name // res: String = Dave Gurnell
  6. ノート:クラス宣言文法 class Name(parameter: type, ...) { declarationOrExpression ... } or

    class Name(val parameter: type, ...) { declarationOrExpression ... } • Name はクラスの名前 • parameter はコンストラクター引数の名前(省略可能) • type はコンストラクター引数の型 • declarationOrExpression は宣言や定義(省略可能) 19
  7. 3.1.3 デフォルト引数とキーワード引数 デフォルト引数値を指定して定義できます。 def greet(firstName: String = "Some", lastName: String

    = "Body") = "Greetings, " + firstName + " " + lastName + "!" greet("Awesome") // res: String = Greetings, Awesome Body! キーワードとデフォルト引数値を組み合わせることで、前の引数をスキップして後の引数 を指定することができます。 greet(lastName = "Dave") // res: String = Greetings, Some Dave!
  8. ノート:キーワード引数 キーワード引数は引数の数や順番の変更に対して頑健にする。例えば、title 引数を greet メソッドに追加した場合、キーワードのないメソッド呼び出しの意味は変わるが、 キーワードのあるメソッド呼び出しの意味は同じである。 def greet(title: String =

    "Citizen", firstName: String = "Some", lastName: String = "Body") = "Greetings, " + title + " " + firstName + " " + lastName + "!" greet("Awesome") // これは現状正しくない // res: String = Greetings, Awesome Some Body greet(firstName = "Awesome") // これは依然正しい // res: String = Greetings, Citizen Awesome Body これは引数の多いメソッドやコンストラクターを作成するときに便利である。 24
  9. 3.1.4 Scala の型階層 Scala は Any という最上位の基底型を持ち、AnyVal と AnyRef という2つの型がその

    下に存在します。AnyVal はすべての値型の基底型で、AnyRef はすべての参照型やク ラスの基底型です。 いくつかの型は単純に Java に存在する型のエイリアスで、Int は int、Boolean は boolean、AnyRef は java.lang.Object です。
  10. 3.1.4 Scala の型階層 Scala には2つの特殊な型が最下層に存在します。Nothing は throw 式の型です。Null は null

    値の型です。それらの特殊な型はすべての型の派生型で、下記のコードが描き 出すように健全さが維持されています。 def badness = throw new Exception("Error") // badness: Nothing null // res: Null = null val bar = if (true) 123 else badness // bar: Int = 123 val baz = if (false) "it worked" else null // baz: String = null
  11. 3.2.1 apply メソッド Scala の関数プログラミングをサポートする機能である関数適用文法を見ていきます。 Scala では apply メソッドを持つオブジェクトを関数のように呼び出せます。 class

    Adder(amount: Int) { def apply(in: Int): Int = in + amount } val add3 = new Adder(3) // add3: Adder = Adder@1d4f0fb4 add3(2) // add3.apply(2) のショートハンド // res: Int = 5
  12. 3.4 ケースクラス ケースクラスを定義するとき、Scala はクラスとコンパニオンオブジェクトを自動的に生成 します。 val dave = new Person("Dave",

    "Gurnell") // クラス // dave: Person = Person(Dave,Gurnell) Person // コンパニオンオブジェクト // res: Person.type = Person さらに、いくつかの便利な機能がクラスとコンパニオンオブジェクトに生成されます。
  13. 3.4.1 ケースクラスの機能 3. オブジェクトのフィールド値を扱う実用的な equals メソッドと hashCode メソッド List や

    Set、Map のようなコレクションでケースクラスを容易に取り扱えます。これは、オ ブジェクトの参照ではなく、オブジェクトの内容にもとづいて比較できるということになりま す。 new Person("Noel", "Welsh").equals(new Person("Noel", "Welsh")) // res: Boolean = true new Person("Noel", "Welsh") == new Person("Noel", "Welsh") // res: Boolean = true
  14. 3.4.1 ケースクラスの機能 4. 同じフィールド値で新しいオブジェクトを生成する copy メソッド dave.copy() // res: Person

    = Person(Dave,Gurnell) copy メソッドはクラスの新しいオブジェクトを作成して返すことに注意します。 dave.copy() eq res // res: Boolean = false
  15. ノート:値と参照の等価性 Scala の == 演算子は Java と異なる。それは参照の同一性を比較するかわりに equals メソッドに委譲する。 Scala

    には Java の == と同じ振る舞いをする eq 演算子がある。しかし、めったにアプ リケーションコードでは使用されない。 new Person("Noel", "Welsh") eq (new Person("Noel", "Welsh")) // res: Boolean = false dave eq dave // res: Boolean = true 57
  16. 3.4.2 ケースクラスコンパニオンオブジェクトの機能 コンパニオンオブジェクトは、クラスのコンストラクターと同じ引数の apply メソッドを含み ます。Scala プログラマーは、new を省略して簡潔にするために、コンストラクターより apply メソッドを好むことで、式中でのコンストラクターを読みやすくします。

    Person("Dave", "Gurnell") == Person("Noel", "Welsh") // res: Boolean = false Person("Dave", "Gurnell") == Person("Dave", "Gurnell") // res: Boolean = true コンパニオンオブジェクトはパターンマッチングで使用するための抽出子パターンの実装 コードも含みます。パターンマッチングについては本章で後述します。
  17. ノート:ケースクラス宣言文法 case class Name(parameter: type, ...) { declarationOrExpression … }

    • Name はケースクラスの名前 • parameter はコンストラクター引数の名前(省略可能) • type はコンストラクター引数の型 • declarationOrExpression は宣言や定義(省略可能) 60
  18. 3.4.3 ケースオブジェクト ケースオブジェクトと通常のシングルトンオブジェクトには違いがあります。 case object キーワードはクラスとオブジェクトを定義し、そのオブジェクトはそのクラス のインスタンスになります。 class Citizen {

    /* ... */ } object Citizen extends Citizen { /* ... */ } ケースオブジェクトはケースクラスに定義される機能のすべてを備えています。 * 訳注:ケースオブジェクトの用途としては列挙型の実装などがあります。
  19. 3.4.4 キーポイント:ケースクラス ケースクラスは Scala のデータ型における必需品です。 ケースクラスを宣言するための文法は、クラスを宣言する文法と同じですが、case が前 置されます。 case class

    Name(parameter: type, ...) { declarationOrExpression ... } ケースクラスはたくさんの自動生成されたメソッドと機能を持ちます。これらの振る舞い を、関連メソッドを実装することで、ひとつひとつオーバーライドすることができます。
  20. 3.5 パターンマッチング 下記のように使用できます。 Stormtrooper.inspect(Person("Noel", "Welsh")) // res: String = Move

    along, Noel Stormtrooper.inspect(Person("Han", "Solo")) // res: String = Stop, rebel scum!
  21. ノート:パターンマッチング文法 expr0 match { case pattern1 => expr1 case pattern2

    => expr2 ... } • expr0 はマッチする値に評価される • パターン(ガード)pattern1, pattern2, ... はマッチする値に対して 順に検証される • 最初にマッチしたパターンの右辺の式 expr1, expr2, ... が評価される* パターンマッチングは式で、マッチした式の値に評価される。 68 * 実際には、パターンは順番にテストするより効率的な形式にコンパイルされるが、その意味は同じである。
  22. 3.5.2 キーポイント:パターンマッチング ケースクラスはパターンマッチングという相互作用の新しい形式を可能にします。パターン マッチングは一致するケースクラスに応じて異なる式を評価します。 expr0 match { case pattern1 =>

    expr1 case pattern2 => expr2 ... } パターンは下記のいずれかになります。 1. 名前。どんな値もマッチし、名前に束縛される。 2. アンダースコア。どんな値もマッチし、無視される。 3. リテラル。リテラルの値とマッチする。 4. ケースクラスのコンストラクタースタイル文法。