Scala/クラス

Scala/クラス

定義する

Scala のクラスは Java のように1ファイル1クラスではないし、ファイル名とクラス名を一致させる必要もない。 好きに作れる。ディレクトリ構成に関しては パッケージ構成

var でフィールドを定義して、def でメソッドを定義する。簡単である。

class Hoge {
  var piyo:Int = 123
  def fuga(a:Int):Int = {
    piyo + a
  }
}

フィールドへのアクセス

外部から

フィールドへのアクセスはフィールド名そのままでできる

var hoge: Hoge = new Hoge()
hoge.piyo = 234
println(hoge.piyo)

しかし実際は暗黙的にメソッドが呼び出されている。 フィールドを作ると同時に

def piyo = {
  piyo
}
def piyo_=(v:Int) = {
  piyo = v
}

が自動的に定義されてこれが呼び出される。この2つのメソッドは特殊なメソッドで通常のメソッドとは違う呼び出し方ができるというものである。

メソッドは何もつけなければ基本的にスコープは Java で言う public に設定される。

内部から

内部からのアクセスは Java 同様に普通に書けばよい。this で明示することもできる。

class Hoge {
  var piyo = 1
  def fuga = {
    piyo = 2
    piyo = 3
    this.piyo
  }
}

コンストラクタ

Scala にコンストラクタは無く、クラスのむき出しになった部分がそのまま実行される。

class Hoge {
  println("Go!")
  var piyo:Int = 123
  def fuga(a:Int):Int = {
    piyo + a
  }
  println("End!")
}

このへんの機構は JavaScript そっくりである。

つまりパラメータが必要ならばこうすればよい

class Hoge(name:String) {
  println(name)
  println("Go!")
  var piyo:Int = 123
  def fuga(a:Int):Int = {
    piyo + a
  }
  println("End!")
}

コンストラクタを沢山作る

class Hoge(name:String) {
  println(name)
  println("Go!")
  def this() = {
    this("aaaa")
  }
  var piyo:Int = 123
  def fuga(a:Int):Int = {
    piyo + a
  }
  println("End!")
}

このように this キーワードを使う。コンストラクタの中では別のコンストラクタを必ず呼ばないといけない。 つまり最外のオリジナルのコンストラクタは必ず呼ばれるということになる。

メソッド

クラスの操作として実装される関数がメソッドである。

引数が無いメソッドの宣言

インスタンスからなんらかの値を単純に返す場合は

class Hoge {
  def piyo = {
    123
  }
}

このように単純にメソッド名に処理を入れ込む形で書く

引数は無いがそれを実行することでインスタンスの内部状態が変わったりする副作用を伴う場合は

class Hoge {
  var fuga:Int = 123
  def piyo() = {
    this.fuga = 345
  }
}

このように括弧付きで宣言する。括弧付きで宣言しておかないと。Scala では括弧付きで呼び出せないのだ。

コーディング規約として副作用を伴うメソッドは括弧付きで呼び出すのが作法(なしでも呼び出せる)なのでこのようにする。

メソッドのオーバーロード

つまり、同名メソッドの引数の数とか型違い。Scala でもできる。

caseクラス

Scala 文法中でうまく使うためのメソッドが予め定義された状態でクラスが作れる

case class Hoge {
}

スコープ

public

Scala では何も付けなければ自動的に public でどこからでもアクセス可能になる

private

同一クラスやそのオブジェクトからアクセス可能

private var hoge:Int = 1

private キーワードを使う

protected

Java の protected は糞仕様で、パッケージからは public になってしまうという謎な挙動だったが、 Scala は、サブクラスからのみOKになるという極めて普通な挙動になる。

継承

Scala のクラス継承はJava の継承とほぼ同じである。

class Hoge {
}
class Piyo extends Hoge {
}

継承した場合のコンストラクタ

親クラスのコンストラクタを使う場合

class Hoge(aaa:Int) {
}
class Piyo(aaa:Int) extends Hoge(aaa) {
}

このように、自身のコンストラクタへのパラメータを継承元に横流しするという、記述をする。 これは、継承する時に(複数あるであろう)親のコンストラクタを1個選ばないといけないということ?

これは JavaScript の apply を利用した this 取り替えの継承と形式となんとなく似ている

継承の禁止

final キーワードをつけると継承禁止になる

final class Hoge {
}

抽象クラス

abstract キーワードを使うと抽象クラスを作成できる。そこで宣言だけで初期化を省略するとそれぞれ抽象フィールド、抽象メソッドとなってサブクラスでの実装を強制できる。

abstract class Hoge {
  val piyo:Int
  def fuga():Int
}

当然抽象クラスなので new できない

オーバーライド

つまり、スーパークラスと同名メソッドを上書きすること。上書きする場合は override キーワードを使って、同名メソッドを作成する

override def hoge() = {
}

値を入れるだけのクラスを作る

一般的にバリューオブジェクトと呼ばれるメソッドは無く単に値を入れるだけの目的でクラスを作ることがよくある

この場合 Scala では非常に簡素に書くことができるようになっている。

case class HogeHoge(name:String, age,Int)

これだけで完了である。 1行で済むのでワザワザファイルを作ってクラスを別個に定義しなくても使う場所の真横で作れる手軽さである。

特殊なメソッド

apply メソッド

クラスで apply という名前を持つメソッドはメソッド名を省略して、括弧だけで呼び出せるようになる

class Hoge {
  var v1:Int = 10
  var v2:Int = 20
  var v3:Int = 30
  def apply(v:Int) {
    v match {
      case 1 => this.v1
      case 2 => this.v2
      case 3 => this.v3
    }
  }
}

と作ると、このように呼び出せる

var hoge:Hoge = new Hoge()
println(hoge(2)) // => 20

クラス自体が配列や連想配列のような入れ物を表現する場合に、この記法を使うとまるでそういう文法があって直接的に内部にアクセスしているように書けるのでよく使われる

updateメソッド

class Hoge {
  var v1:Int = 10
  var v2:Int = 20
  var v3:Int = 30
  def update(k:Int, v:Int) {
    k match {
      case 1 => this.v1 = v
      case 2 => this.v2 = v
      case 3 => this.v3 = v
    }
  }
}

と作ると、このように呼び出せる

var hoge:Hoge = new Hoge()
hoge(2) = 40

クラス自体が連想配列的な機能を持つ場合、update という名前のメソッドを、あたかもキー指定で代入しているように使えるという記法である。

非常に紛らわしいが

var hoge:Hoge = new Hoge()
hoge.update(2, 40)
hoge(2) = 40

この2つは同じ

piyo_= piyo

メソッド名がアンスコイコールで終わっているメソッドは setter として簡素に使えるようになっている。 これとセットで

class Hoge {
  var v:Int = 10
  def piyo_=(v:Int) {
    this.v = v
  }
  def piyo = {
    this.v
  }
}

と作ると、このように呼び出せる

var hoge:Hoge = new Hoge()
hoge.piyo = 123
println(hoge.piyo)

この2つのメソッドはセットで作成する必要がある

scala/class.txt · 最終更新: 2020-08-03 13:17 by ore