学んだことをなぐり書き


オブジェクトは初めてアクセスされたときに初期化される

object A {
  // println("2")の後 A にアクセスされるので 2 -> 1 の順で表示される。
  println("1")
}

println("2")
println(A)
2
1
Main$$anon$1$A$@125b8827

オブジェクトインポート

/**
 * javaのstatic importのようなもの
 * 現在のスコープ範囲内でインポートしたオブジェクトのpublicを取り込める。
 */
object A {
  def sayA = println("a")
  private def sayA2 = println("a2")
}
import A._

sayA
// private にはアクセスできない
// snayA2

// javaと違いオブジェクトならば途中で生成したインスタンスでも取り込める。
// ただし var だとエラーが出る。
class B(s: String) { def sayB = println(s) }
val b = new B("bbbb")
import b._

sayB
a
bbbb

パラメーターなしメソッド

/**
 * scalaは統一形式アクセスの原則(uniform access principle)に従っている。
 * 「属性をフィールドとメソッドのどちらで実装するかによってクライアントコードが影響を受けてはならない」
 * def のほうが毎回計算されるのでわずかながら遅くてメモリを消費する。
 * 最初 val で定義しておき、なんらかの処理(値のチェックなど)が必要になった場合
 * 途中で def に変更してもクライアントには影響を及ぼさない。
 */
object A {
  val width = 10
}
object B {
  // ただの値の参照のみで副作用がないので () なし。
  def width = 10
}
object C {
  var random = 0
  // 変数の変更やI/O処理など副作用を伴うので () をつけたほうがいい
  def change() {
    random = (new util.Random).nextInt(5)
    println(random)
  }
}
println(A.width)
println(B.width)
// 括弧なしでも呼びだせるが副作用が伴う時は () があったほうがいい
C.change
C.change()
10
10
0
3

フィールドとメソッドの名前空間は一緒

http://yanana.github.com/scala-style/naming_conven...
/**
 * Scalaではフィールドとメソッドが同じ名前空間に属している。
 * つまり同じ名前のメソッドとフィールドを定義できない。
 * おすすめはフィールドの前置に _ を置くこと。
 * 後置に _ を置くと name _(関数リテラルに変換)と間違えるので前置のほうが好ましい。
 */
object O {
  // コンパイルエラー
  // private var f = 0
  private var _f = 0
  def f = 1
}

// 逆に利点として名前空間が一緒なので
// def で定義したものを val(var はダメ) で override することが出来る。
// val で定義して def で override することは出来ないっぽい。
class C {
  def str = "C"
}
class C2(override val str: String) extends C
val obj: C = new C2("C2")
println(obj.str)
C2

比較演算子(==) の振舞いを変更する

/**
 * 通常のオブジェクト同士の比較の場合、参照先が同じかどうかの比較が行なわれる。
 * equals を override すると 比較演算子(==) の振舞いを変更できる。
 * String や Array などの == では参照の比較でなく値の比較を行なっている。
 */
class Other(val a: Int*)
class C(val a: Int*)
class C2(a: Int*) extends C(a:_*) {
  // C に変換できるものは val a の比較を行なう。それ以外 false
  override def equals(that: Any): Boolean = {
    if (!that.isInstanceOf[C]) return false
    val c = that.asInstanceOf[C]
    a == c.a
  }
}
val o = new Other(0, 1, 2)
val (c1, c2) = (new C(0, 1, 2), new C(0, 1, 2))
val (c3, c4, c5) = (new C2(0, 1, 2), new C2(0, 1, 2), new C2(3, 4, 5))
println("c1 == c2: " + (c1 == c2))
println("c3 == c1: " + (c3 == c1))
println("c3 ==  o: " + (c3 ==  o))
println("c3 == c4: " + (c3 == c4))
println("c3 == c5: " + (c3 == c5))
c1 == c2: false
c3 == c1: true
c3 ==  o: false
c3 == c4: true
c3 == c5: false

コンパニオンクラス・オブジェクト

/**
 * シングルトンオブジェクトがクラスと同じ名前を持つとき
 * そのクラスはコンパニオンクラスと呼び、
 * オブジェクトの方はコンパニオンオブジェクトと呼ぶ。
 * コンパニオンクラスとオブジェクトは同じソースファイル内に定義しなければならない。
 * コンパニオンクラスとオブジェクトはお互いのprivateにアクセスすることが出来る。
 */
class A {
  private var num = 0
  private def print = println(num)

  def access {
    // コンパニオンオブジェクトのprivateにアクセスできる
    A.num = 40
    A.print
  }
}

object A {
  private var num = 0
  private def print = println(num)

  def access {
    var a = new A
    // コンパニオンクラスのprivateにアクセスできる
    a.num = 30
    a.print
  }
}

var a = new A
// 通常なら private にはアクセスできない。
// a.num
// a.print
// A.num = 10
// A.print 
a.access
A.access
30

メンバーのみ編集できます