背景
このような Semigroup のトレイトがあり、
trait Semigroup[A] {
def append(a1: A, a2: => A): A
}
こういうことができる。
scala> val x: Semigroup[String] = (a1, a2) => a1.toUpperCase + a2.toUpperCase
x: Semigroup[String] = $$Lambda$1229/1427479449@77724c7d
突然のラムダ式で Semigroup[String]
を生成している。
Java でいう Functional Interface 的な感じ?かと思ったがよくわからなかったので調べてみた。
SAM type (Single Abstract Method type)
Scala のラムダ式は trait に自動変換できる - Qiita
abstract method が一つだけ定義された trait は、ラムダ式から変換できるらしい。 @xuwei_k 先生曰く、2.12 から入った機能とのこと。 SAM conversion と呼ばれている。
なるほど、たしかに上記の Semigroup は、抽象メソッドを 1つだけもつ trait である。
試しに抽象メソッドを複数にしたらコンパイラに怒られた。
trait Semigroup[A] {
def append(a1: A, a2: => A): A
def hoge(a1: A, a2: => Int): A //2つ目の抽象メソッド
}
先程のラムダ式のところで型を指定しろと怒られる。
scala> val x: Semigroup[String] = (a1, a2) => a1.toUpperCase + a2.toUpperCase
<console>:14: error: missing parameter type
val x: Semigroup[String] = (a1, a2) => a1.toUpperCase + a2.toUpperCase
^
<console>:14: error: missing parameter type
val x: Semigroup[String] = (a1, a2) => a1.toUpperCase + a2.toUpperCase
^
で、型を指定しても怒られる。
なぜなら、複数の抽象メソッド → Java でいう Functional Interface じゃない → SAM 型じゃなくて普通の FunctionN になる。からだと思う。
scala> val x: Semigroup[String] = (a1: String, a2: String) => a1.toUpperCase + a2.toUpperCase
<console>:14: error: type mismatch;
found : (String, String) => String
required: til.sam_conversion.Semigroup[String]
val x: Semigroup[String] = (a1: String, a2: String) => a1.toUpperCase + a2.toUpperCase
抽象メソッドじゃない普通のメソッドは追加しても大丈夫。
trait Semigroup[A] {
def append(a1: A, a2: => A): A
def hoge(a1: A, a2: => Int): A = a1 //a1をそのまま返す普通のメソッド
}
Scala 2.12.0 リリースノート | eed3si9n
トレイトはインターフェイスにコンパイルされる
SAM型に対するラムダ構文