为什么类val参数不能按名称调用?

acj*_*jay 5 scala

我正在尝试使用一个类作为单个接口聚合一堆API函数的代理.其中一些是nullary函数,但我不希望将它们包含在类构造函数中以触发API调用.我现在的解决方案是将调用包装在一个文字的nullary函数中new myClass(() => apiCall),然后显式调用成员函数.这并不是那么糟糕,但我想知道是否有技术原因我不能只使用call-by-name参数来传递对方法的延迟引用?

例:

scala> class MyClass(val apiCall: => String)
<console>:1: error: `val' parameters may not be call-by-name
       class MyClass(val apiCall: => String)
Run Code Online (Sandbox Code Playgroud)

编辑我应该指定我的问题是为什么类不能有val参数.添加了一个示例.

sjr*_*jrd 5

一个类可以很好地具有按名称调用的参数,只要它们不是val或者var:

> scala
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class Foo(f: => Unit) {
     |   def run(): Unit = f
     | }
defined class Foo

scala> new Foo(println("hello"))
res0: Foo = Foo@5da6b8c6

scala> res0.run()
hello
Run Code Online (Sandbox Code Playgroud)

a valvar参数不能是名字的原因很简单,就是这个问题,类字段不能是名字,也不能是本地变量.所以以下内容无效:

scala> class FooInvalid(val v: => Unit) {
<console>:1: error: `val' parameters may not be call-by-name
       class FooInvalid(val v: => Unit) {
                               ^
Run Code Online (Sandbox Code Playgroud)

但是,它可能有一个分配,一个通过名字参数作为函数val领域,像这样(但你必须使用()呼叫网站):

scala> class FooVal(v0: => Unit) {
     |   val v: () => Unit = () => v0
     | }
defined class FooVal

scala> new FooVal(println("hello"))
res2: FooVal = FooVal@75c145bc

scala> res2.v
res3: () => Unit = <function0>

scala> res2.v()
hello
Run Code Online (Sandbox Code Playgroud)

最后,您可以将其定义vval类型,而不是定义为类型.然后你会得到你可能想要的行为:() => UnitdefUnit

scala> class FooDef(v0: => Unit) {
     |   def v: Unit = v0
     | }
defined class FooDef

scala> new FooDef(println("hello"))
res5: FooDef = FooDef@2e04a041

scala> res5.v
hello
Run Code Online (Sandbox Code Playgroud)

有人可能会争辩说编译器本身应该进行这种转换,但这与val必须稳定的语义不一致(例如,你import x._的成员可以使用稳定的值,而不能用不稳定的值做),因为a def(即使没有())是一个不稳定的价值.最好将这个小的重写留给用户,而不是引入一个非常奇怪的不健全.