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

时间:2014-07-09 20:21:48

标签: scala

我试图使用一个类来聚合作为单个接口的一堆API函数代理。其中一些是无效函数,但我不希望在类构造函数中包含它们以触发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)

修改我应该指明我的问题是为什么课程不能有val参数。添加了一个示例。

1 个答案:

答案 0 :(得分:5)

只要不是valvar,类就可以使用按名称调用的参数:

> 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

valvar参数不能是名字的原因仅仅是类字段不能是名字,也不能是本地变量。所以以下内容无效:

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

但是,可以将一个名称参数指定为作为函数val字段,就像这样(但是你必须使用{{1作为呼叫站点):

()

最后,您可以将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 定义为类型为v的{​​{1}},而不是将val定义为() => Unit类型def。然后你会得到你可能想要的行为:

Unit

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