我试图使用一个类来聚合作为单个接口的一堆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
参数。添加了一个示例。
答案 0 :(得分: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
val
或var
参数不能是名字的原因仅仅是类字段不能是名字,也不能是本地变量。所以以下内容无效:
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
)是一个不稳定的值。最好把这个小的重写留给用户,而不是引入一个非常奇怪的不健全。