Scalaの基礎まとめ その2

ChainZ(クリエイター)
いろいろやってます。

この記事はhttp://befool.co.jp/blog/chainzhang/basic-of-scala-1/の引き続きです。

クラス

ScalaはOOPによく使うclassというコンセプトもしっかりサポートしています。Scalaのクラスにはcase classclass二種類ある。case classは関数型プログラミングに特化したクラスであって、全てのメンバー変数がvalタイプになる。

1
2
3
4
5
6
7
8
9
class People(var name: String, val age: Int)
case class Animal(name: String, age: Int)

val p = new People("Hoge", 21)
p.name = "Mori"
println(p.name) // "Mori"

val a = new Animal("cat", 3)
a.name = "dog" // ERROR!

Class

Scalaのclassの定義は関数と少し似ています、しかし、引数がそのままclassのプロパティー(メンバー変数)になります。なお、scalaはプロパティーのタイプによって、自動的にgetterとsetterを作成します。

タイプ 権限
var GetterとSetter両方作成します |
val Getterのみ作成します |
private var GetterとSetter作成しません、class内アクセスのみ |
private val GetterとSetter作成しません、class内アクセスのみ |
<空> case classの場合はprivate valになる, classの場合はprivate varになる |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Player(var name: String, var score: Int = 0) {
  override def toString : String = s"$name : $score"
}
object NonePlayer extends Player(score = 0, name = "")
// objectはsingletonです、最初のアクセスのみで初期化します。

class Eva(
  val name: String,
  var power: Int = 0,
  private var _pilot: Player = NonePlayer)
// pilotのsetterとgetterをカスタマイズするので、privateにします
{
  // pilot getter
  def pilot: Player = _pilot

  // pilot setter
  def pilot_=(p: Player): Unit = {
    power = p.score
    _pilot = p
  }

  override def toString = _pilot match {
    case NonePlayer => s"[無人]$name(power: $power)"
    case _ => s"$name(power: $power, pilot: ${_pilot.name})"
  }
  // matchはScalaでよく使うメソードです、他の言語だとswitchのようなものだが、switchよりパワフルです。
}

val e = new Eva("初号機")
println(e) // [無人]初号機(power: 0)
e.pilot = new Player(name = "Shinji", score = 9000)
println(e) // 初号機(power: 9000, pilot: Shinji)

この例では、すべて戻り値のタイプを指定していますが、Scalaは十分スマートなので、戻り値のタイプは普通に書かなくても大丈夫です。もちろん、書いたほうがより良いプログラミング習慣を身につけるでしょう。

Object と trait

ScalaのObjactSingletonの作成、classと組んでCompinion Objectを作るとかに使います。traitはScalaでJavaのInterfaceのような役割をしています。JavaのInterfaceよりできること多いです。メソードを既存のclassにインジェクトしたりすることもできる。

1
2
3
4
5
6
7
8
9
10
11
12
// Compinion Object
// Evaクラスのstaticメソードなどは、object Evaの中で定義する
// (Scalaにはstaticというキーワードがないので、staticメソードはclassの中で直接定義できません。)
object Eva {
  var count = 0

  def status = s"Evaが${count}台作成されています"
}
trait EvaCounterTrait {
  Eva.count += 1
  // increase counter
}

既存のEvaクラスにEvaCounterTraitextendsします:

1
2
3
4
5
class Eva(
  val name: String,
  var power: Int = 0,
  private var _pilot: Player = NonePlayer
) extends EvaCounterTrait

すると、newで作成されたEvaの数がEva.statusで見れるようになります。

まとめ

Scalaを勉強して2週間ぐらい経って、文法に慣れつつあるものの、Funcation Programming(関数型プログラミング)の思考などに結構難航しています。FPをやると少し高度な数学知識(大学レベル)が必要だなと実感しています。でもScalaは少ないコードで安定したアプリを作れるというとこが魅力で、これからも長く付き合おうと思っています。

ちなみに、この記事は初心者向けて書いています。細かいところは省略しています。もし「Scalaが面白そう」と思ってもらえれば嬉しいです。