Scala 例 文字列 String

ScalaのStringについて、調べてみる。暗黙の型変換、implicit defの話題もある。

ScalaのStringは、Javajava.lang.Stringそのもの。

scala> val a = "abcd"
a: java.lang.String = abcd

scala> a.getClass
res14: java.lang.Class[_] = class java.lang.String

さすがに、なんでも自前で用意ってわけじゃないんだな。再利用、再利用。

はなしが変わるけど、Scala Standard Library 2.12.8 - scala.Predefには、type Stringが定義してある。この場合は、単純に、java.lang.Stringに対して、短い別名Stringを定義しているだけのようだ。

type String = java.lang.String


ここまでは「typeなんてあるんだ。ふーん」って感じだが、Scalaを学びはじめているときには、Stringには、ちょっとおもしろいところがある。

それは、ただのjava.lang.Stringオブジェクトのはずなのに、java.lang.Stringにはないメソッドがつかえるところ。

scala> "abcd"
res19: java.lang.String = abcd

scala> "abcd".toList
res20: List[Char] = List(a, b, c, d)

scala> "%04d".format(100)
res21: String = 0100

java.lang.Stringについては、toListメソッドなんてないし、formatメソッドも、staticメソッドであり、また、うえの例のような、シグニチャではない。

Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle

ちょっと、ScalaのStringを調べてみると、

scala> "abcd".getClass.getMethods.filter(_.getName == "toList")
なにもない

scala> "abcd".getClass.getMethods.filter(_.getName == "format").foreach(println)
public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])
public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])

上のように、ありもしないメソッドを実行できるように見えるのは、Scalaの暗黙の型変換とよばれる機能によるもの。
あらかじめimplicit defで定義しておくと、必要に応じて、あるクラスのオブジェクトが別のクラスのオブジェクトに変換される。

java.lang.Stringについて、ふたたびScala Standard Library 2.12.8 - scala.Predefを見ると、

implicit def augmentString(x: String): StringOps = new StringOps(x)

が定義してある。

これによって、java.lang.Stringオブジェクトは、Scala Standard Library 2.12.8 - scala.collection.immutable.StringOpsオブジェクトに自動的に変換される。

ソースコードとしては、パッと見て、java.lang.Stringオブジェクトをあつかっているはずなのに、Scala Standard Library 2.12.8 - scala.collection.immutable.StringOpsオブジェクトをあつかっているかのように記述することができる。

繰り返しになるが、java.lang.Stringにないメソッドが、いろいろ使えるようになる。

Scalaは、妙に機能豊富なところがあって、「気持ちわるい」「わかりづらい」という気がしなくもない。あるとき、突然、当たり前に便利に感じるようになるのかな。

下の例では、StringOpsのメソッドにより、Stringについて、正規表現のパターンを生成したり、Listに変換したり。

scala> val p = "([A-Z])".r
p: scala.util.matching.Regex = ([A-Z])

scala> "abCdEf".toList
res67: List[Char] = List(a, b, C, d, E, f)