我正在尝试使用一个类作为单个接口聚合一堆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参数.添加了一个示例.
一个类可以很好地具有按名称调用的参数,只要它们不是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 val或var参数不能是名字的原因很简单,就是这个问题,类字段不能是名字,也不能是本地变量.所以以下内容无效:
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)
最后,您可以将其定义v为val类型,而不是定义为类型.然后你会得到你可能想要的行为:() => 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(即使没有())是一个不稳定的价值.最好将这个小的重写留给用户,而不是引入一个非常奇怪的不健全.