S-JIS[2015-09-22] 変更履歴

Scala識別子

Scalaの識別子(クラス名やメソッド名・変数名等)のメモ。


識別子

クラス名やパッケージ名、メソッド名・変数名等のことを識別子と呼ぶ。

Scalaでは、(Javaと同じく)半角英数字・アンダースコア「_」や、いわゆる全角文字が識別子として使える。
(識別子を数字で始めることは出来ない)
アンダースコア1文字のみでは識別子として使用できない)

また、Scalaでは「+」や「-」といった記号も識別子として使用できる。
予約語(キーワード)として定義されている単語も、バッククォートで囲むことで使用できる。

メソッド名として使用する識別子(単語)では、applyやupdateのように、特別な役割が割り当てられているものもある。
特殊なメソッド名


記号を識別子として使用する方法

Scalaでは、「+」や「-」といった記号も識別子として使用できる。

主にメソッドとして定義することで、中置記法を使って式のように記述することが可能になる。

case class Hoge(val n: Int) {
  def +(other: Hoge) = Hoge(n + other.n)
}

scala> println(Hoge(123) + Hoge(456))
Hoge(579)

記号を使ってメソッドを定義した場合の演算の優先順位
記号を使って識別子を定義した場合のJavaでの名前

ただし、ピリオド「.」やコロン「:」セミコロン「;」といった、Scalaの文法上で使用されている文字は使用できない。
これらの記号でもバッククォートで囲めば使用できるが、あまり綺麗ではない^^;

class `.` {
  def `.` = "."
}

scala> println(new `.`().`.`)
.

ちなみに、「+」や「-」も変数名として定義できるが、使う場面では演算子としての解釈が優先されるようなので、実際には使えない。

scala> val + = 123
+: Int = 123

scala> println( + )
<console>:1: error: illegal start of simple expression
       println( + )
                  ^

ただしこれが駄目なのは、「+」や「-」が別の場所で単項演算子として定義されているから、単項演算子のみが指定されたように見える為。
単項演算子と変数を並べる書き方(「+1」のような)だと使える。

scala> println(+ +)
123

scala> println(- +)
-123

単項演算子でない「*」や「/」は使うことが出来る。

scala> val * = 10
*: Int = 10

scala> println(*)
10

scala> println(* * *)
100

scala> println(***)
<console>:8: error: not found: value ***
       println(***)
               ^		←空白を入れないと、まとめて1つの識別子として判断されるので、エラー

まぁ、見てのとおり訳が分からなくなるので、変数名としては記号は使わない方がいいだろうね^^;


なお、アンダースコア「_」1文字のみだと、識別子として使用できない。

scala> class _
<console>:1: error: identifier expected but '_' found.
       class _
             ^
scala> class `_`
<console>:1: error: wildcard invalid as backquoted identifier
       class `_`
             ^
scala> val _ = 123
<console>:5: error: wildcard invalid as backquoted identifier
  lazy val $result = `_`
                                          ^
<console>:10: error: wildcard invalid as backquoted identifier
 + "_: Int = " + scala.runtime.ScalaRunTime.replStringOf(`_`, 1000)
scala> val `_` = 123
<console>:1: error: wildcard invalid as backquoted identifier
       val `_` = 123
           ^

Scalaではアンダースコア1文字「_」はワイルドカード等に使っているので、識別子として使えないようになっているのだろう。


キーワード(予約語)を識別子として使用する方法

Scalaの予約語となっている単語でも、識別子(クラス名やパッケージ名、メソッド名・変数名)として使用することが出来る。[2010-12-07]

例えばmatchyieldはScalaの予約語(特別な意味・文法を持つ単語)なので、そのまま使うとコンパイルエラーになる。

scala> val match = 1
<console>:1: error: illegal start of simple pattern
       val match = 1
           ^

scala> Thread.yield()
<console>:1: error: identifier expected but 'yield' found.
       Thread.yield()
              ^
↑「identifier」は識別子(ここではメソッド名)のこと。つまり「識別子が来るはずなのに予約語yieldを見つけたぞ」というコンパイルエラー

こうした場合に単語をバッククォート「`」でくくると、識別子として扱われる。

scala> val `match` = 1
match: Int = 1

scala> Thread.`yield`()

予約語でない単語の場合、バッククォートで囲っても囲まなくても同じものとして扱われる。[2015-09-22]

scala> val `abc` = 123; println(abc)
123
abc: Int = 123

scala> val zzz = 456; println(`zzz`)
456
zzz: Int = 456

ちなみにJava(JDK1.6まで)では、予約語をScalaの様に識別子として扱う方法は無い。
なのでJDK1.4でassertという単語が新しく予約語になった際、JDK1.3でassertという識別子を使っているソースはそのままではJDK1.4でコンパイルできなかった。なので-source 1.3オプションを使ってわざわざ古いバージョンでコンパイルしてみたり…(苦)
JDK1.5でもenumで同じ問題が起きる。
JDK1.7では、新しい予約語が解釈される範囲を限定することで、そういったことが無いようになる…という噂だったが、JDK1.7では新しい予約語は追加されていない。


Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま