学習メモ: クラス (2/2) #dwango #Scala
この記事について
ドワンゴScala研修テキストを学習したときのメモです。 okoysm.hatenablog.jp
前回はこちら okoysm.hatenablog.jp
DOING
クラス
メソッド定義
メソッド本体が1つの式だけからなる場合
基本形(実態)。
(private[this/package名]/protected[package名]) def methodName(parameter1: Type1, parameter2: Type2, ...): ReturnType = ???
一般的な定義
={}
を使ったスタイルのほうが{}
内に複数の式を並べて書けることを利用した派生形。- こっちのパターンのほうが使うことは多い
(private[this/package名]/protected[package名]) def methodName(parameter1: Type1, parameter2: Type2, ...): ReturnType = { ??? }
返り値の型は明記しよう
- 省略しても特別な場合以外は型推論してくれるけれども、読みやすさのために明記する習慣をつけよう
- 個人的にはこれがいいから静的型付け言語好き
アクセス権
- アクセス権は3種類 (private, protected, public)
Scala独特のアクセス権まわりの書き方
- private[this]:同じオブジェクトからのみアクセスが可能
- private[package名]:同一パッケージに所属しているものからのみアクセスが可能
- protected[package名]:派生クラス+同じパッケージに所属しているもの全てからアクセスできるようになる
メソッドを実装してみる
メソッド名に+を指定できるのが衝撃だった
scala> class Point(val x: Int, val y: Int) { | def +(p:Point): Point = { | new Point(x + p.x, y + p.y) | } | override def toString(): String = "(" + x + ", " + y + ")" | } defined class Point scala> val p1 = new Point(1, 1) p1: Point = (1, 1) scala> val p2 = new Point(2, 2) p2: Point = (2, 2) scala> p1+p2 res0: Point = (3, 3)
複数の引数リストを持つメソッド
メソッドは複数の引数リストを持つように定義することができる
def methodName(parameter11: Type11, parameter12: Type12, ...)(...)(parameterN1: TypeN1, ..., parameterNM: TypeNM): RerurnType = ???
用途
実装してみる
複数の引数リストを持つ加算メソッドを定義してみる。
- 複数の引数リストを持つメソッドはobj.m(x)(y)の形式で呼びだす
- 一番下のように、最初の引数だけを適用して新しい関数を作る(部分適用)こともできる
scala> class Adder { | def add(x: Int)(y: Int): Int = x + y | } defined class Adder scala> val adder = new Adder() adder: Adder = Adder@5132ea8c scala> adder.add(2)(3) res2: Int = 5 scala> adder.add(2) _ res3: Int => Int = $$Lambda$1791/569849097@1ceeb7d7
疑問点
- 複数の引数リストを持つメソッドで、最初の引数だけを適用して新しい関数を作る(部分適用)の使い所はどこ?
フィールド定義
定義
(private[this/package名]/protected[package名]) (val/var) fieldName: Type = Expression
val/var
- val: 変更不能なフィールドになる
- var: 変更可能なフィールドになる
アクセス権
- private : そのクラス内だけからのみ
- private[this] : 同じオブジェクトのみ
- private[package名] : 同一パッケージからのみ
- protected : そのクラスの派生クラスからのみ
- protected[package名] : 派生クラスと同一パッケージに所属しているもの全て
- なにもつけない:public
private[this]は若干高速
- JVMレベルでのフィールドへの直接アクセスになるため、若干高速
- 細かいレベルでのパフォーマンスチューニングをする場合は意識すると良い
継承
クラスのもう一つの機能が継承
継承の目的
Javaの継承の目的とあんまり変わらん
実装の継承におけるJavaとの違い
ScalaはTrait(次々回)を使うことで複数の実装の継承ができる
実装の継承には複数の継承によりメソッドやフィールドの名前が衝突する場合の振舞いなどに問題があることが知られており、Javaでは実装継承が1つだけに限定されています。 Java 8ではインタフェースにデフォルトの実装を持たせられるようになりましたが、変数は持たせられないなどの制約があります。 Scalaではトレイトという仕組みで複数の実装の継承を実現していますが、トレイトについては別の節で説明します。
通常のクラスの継承の構文
Javaと同じくextends
書く
class SubClass(....) extends SuperClass { .... }
メソッドをoverrideするとき
JavaはアノテーションやJavadocで記載していたが、Scalaでは明示的に書く
scala> class APrinter() { | def print(): Unit = { | println("A") | } | } defined class APrinter scala> class BPrinter extends APrinter { | override def print(): Unit = { | println("B") | } | } defined class BPrinter scala> new APrinter().print A scala> new BPrinter().print B
この章での疑問点
- コンストラクタの引数をそのまま公開したくない場合などあるのだろうか(Javaでいうprivateな変数にしてgetter/setterで取らせたいみたいなやつかな)
- 複数の引数リストを持つメソッドで、最初の引数だけを適用して新しい関数を作る(部分適用)の使い所はどこ?