Locked History Actions

Diff for "scala/callLike"

Differences between revisions 3 and 4
Deletions are marked like this. Additions are marked like this.
Line 70: Line 70:

== update ==

これは読んで字のごとく、オブジェクトを更新することを意図したもの。

{{{
class CallLike {
  def update(i: Int, j:Int, value: String): Unit = { println("update") }
  ...
}
...
    obj(1, 2) = "abc"// update
}}}

ScalaにはJavaと異なり言語組み込み(?)の配列はなく、例えばArrayも普通のオブジェクトであるが、そのオブジェクトを更新するには、このupdateを使う。このときの呼び出しは、当然ながら「[]」ではなく「()」を使うことになる。


{{{
val a = Array(1, 2, 3)
a(0) = 555
... 結果はArray(1, 555, 3)
}}}
あるいは、updateを明示的に呼び出しても同じ
{{{
a.update(0, 555)
}}}

ちなみに、配列の要素を取得する場合は、
{{{
val b = a(0)
}}}
であるが、これはapplyが呼び出されている(と思う)。つまり、以下でも同じ
{{{
val b = a.apply(0)
}}}

メソッド呼び出しのように見えるもの

Scalaの(特殊な?)文法

Scalaにはオブジェクトに対する直接のメソッド呼び出しのように見える構文がある。 これはJavaで言えばnewの無いコンストラクタ呼び出しのようである。

同じような書き方をしても文脈によって動作は異なり、その動作は実際にはupdate,apply,unapplyというメソッドによって定義される。 例えば以下のようなコードを考えてみる。

class CallLike {
  def update(i: Int, j:Int, value: String): Unit = { println("update") }
  def apply(i: Int, j: Int): Unit =  { println("apply") }
  def unapply(value: String) = { println("unapply"); Some(30, 40) }
}
object Main {
  def main(args: Array[String]) {
    val obj = new CallLike();
    obj(1, 2) = "abc"// update
    obj(3, 4) // apply
    val obj(x, y) = "xyz"; // unapply
  }
}

この実行結果は

update
apply
unapply

になる。同じ一つのobjに続けてカッコをつけて引数(及び引数のようなもの)を記述したとしても、文脈によって実際に呼び出されるメソッドが異なる。

  • updateは、右側に代入演算子(?)のついている場合
  • applyは、代入されていない(ように見える)場合
  • unapplyは、変数定義と同時に初期化している(ように見える)場合

もう少し動作確認

本当に期待する通りの動作を行っているのか、確認のために次のように記述してみる。

class CallLike {
  def update(i: Int, j:Int, value: String) = { println("update %d %d %s" format (i, j, value)); 10 }
  def apply(i: Int, j: Int) =  { println("apply %d %d" format (i, j));  20 }
  def unapply(value: String) = { println("unapply %s" format value); Some(30, 40) }
}
object Main {
  def main(args: Array[String]) {
    val obj = new CallLike();
    val updateReturn = obj(1, 2) = "abc"; // update
    println("updateReturn %d" format updateReturn);
    val applyReturn = obj(3, 4) // apply
    println("applyReturn %d" format applyReturn);
    val obj(x, y) = "xyz"; // unapply
    println("unapplyReturn %d %d" format (x, y))
  }
}

この結果は以下。

update 1 2 abc
updateReturn 10
apply 3 4
applyReturn 20
unapply xyz
unapplyReturn 30 40

update

これは読んで字のごとく、オブジェクトを更新することを意図したもの。

class CallLike {
  def update(i: Int, j:Int, value: String): Unit = { println("update") }
  ...
}
...
    obj(1, 2) = "abc"// update

ScalaにはJavaと異なり言語組み込み(?)の配列はなく、例えばArrayも普通のオブジェクトであるが、そのオブジェクトを更新するには、このupdateを使う。このときの呼び出しは、当然ながら「[]」ではなく「()」を使うことになる。

val a = Array(1, 2, 3)
a(0) = 555
... 結果はArray(1, 555, 3)

あるいは、updateを明示的に呼び出しても同じ

a.update(0, 555)

ちなみに、配列の要素を取得する場合は、

val b = a(0)

であるが、これはapplyが呼び出されている(と思う)。つまり、以下でも同じ

val b = a.apply(0)