=> Unit と () => Unit と Unit => Unit の違い
先日、op: Unit => Unit
と書かざるを得ない状況に直面した。それで、この関数を op()
として呼び出したときに「多分あなたが意図していることと違うことしてますよ」みたいなwarningが出て気づいたこと。ScalaのUnitは値がないことを表す型なわけだが、「実際に値がない」のではなく、「値がないことを仮想的に表す値()
」を持つ型であるということ。
具体的なwarningメッセージはこちら。
Warning:(140, 9) Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want. signature: Function1.apply(v1: T1): R given arguments: <none> after adaptation: Function1((): Unit) op() ^
したがって、Unit => Unit
は実際には一つの引数を取って一つの値を返す関数であり、引数を取らない () => Unit
とは別物である。そのため、op()
のように引数が空っぽの呼び出しでは整合性が取れない。
=> Unit
と () => Unit
については理解していたものの、() => Unit
と Unit => Unit
の違いについてきちんと理解していなかった。何もない、という意味で ()
とUnit
は同じものだと勘違いしており、落とし穴にハマってしまった。しかも、なんというか、引数リストの( )
括弧と、値としての()
と、型指定の特殊表記としての() =>
の意味が重なりあって不思議な読みを引き起こしていて、話をややこしくしている。名前や記号に関する整合性を重視するScalaっぽくない仕様という感じがするが、仕方ないのかな…。
以下の解説がよくわかります。
() => Unit
はFunction0が定義されるのに対して、 Unit => Unit
はFunction1となるため、Unit型の値(つまり()
)を引数として取る必要がある。op: Unit => Unit
に対してはop(())
や op(Unit)
とすると警告が解消される。
Unitについてはこちら。