[英]Why can't a class val parameter be call-by-name?
I'm trying to use a class to aggregate as a single interface a bunch of proxies for API functions. 我正在尝试使用一个类将一堆API函数的代理作为单个接口聚合。 A couple of these are nullary functions, but I don't want the act of including them in the class constructor to trigger the API calls.
其中有两个是null函数,但是我不希望将它们包含在类构造函数中来触发API调用。 My solution right now is to wrap the call in a literal nullary function
new myClass(() => apiCall)
and then calling the member function explicitly. 现在,我的解决方案是将调用包装在文字上为null的函数
new myClass(() => apiCall)
,然后显式调用成员函数。 This isn't all that bad, but I'm wondering if there's a technical reason I can't just use a call-by-name parameter to pass lazy reference to the method? 这还不是很糟糕,但是我想知道是否有技术上的原因,我不能仅使用按名称调用参数将延迟引用传递给该方法?
Example: 例:
scala> class MyClass(val apiCall: => String)
<console>:1: error: `val' parameters may not be call-by-name
class MyClass(val apiCall: => String)
Edit I should have specified that my question is why a class can't have a val
parameter. 编辑我应该指定我的问题是为什么一个类不能有
val
参数。 Added an example. 添加了一个示例。
A class can very well have call-by-name parameters, as long as they are not val
or var
: 只要它们不是
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
The reason a val
or var
parameter cannot be by-name is simply that a class field cannot be by-name, no more than local variable, for that matter. val
或var
参数不能按名称命名的原因很简单,就是就此而言,类字段不能按名称命名,只能是局部变量。 So the following is invalid: 因此以下内容无效:
scala> class FooInvalid(val v: => Unit) {
<console>:1: error: `val' parameters may not be call-by-name
class FooInvalid(val v: => Unit) {
^
However, it is possible to have a by-name parameter that is assigned, as a function to a val
field, like this (but then you have to use ()
as call site): 但是,可以像这样向
val
字段分配一个作为函数的by-name参数(但随后必须使用()
作为调用站点):
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
Finally, instead of defining v
as a val
of type () => Unit
, you can define it as def
of type Unit
. 最后,而不是定义
v
作为val
型的() => Unit
,可以根据定义它def
类型的Unit
。 And then you get the behavior you probably wanted in the first place: 然后,您首先获得了可能想要的行为:
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
One could argue that the compiler should do this transformation itself, but that would not be consistent with the semantics that a val
must be stable (eg, with a stable value you can import x._
its members, which you cannot do with an unstable value) since a def
(even without ()
) is a not a stable value. 有人可能会争辩说编译器应该自己进行这种转换,但这与
val
必须稳定的语义不一致(例如,使用稳定值可以import x._
其成员,而对于不稳定对象则不能这样做)值),因为一个def
(即使没有()
是一个不稳定值。 Best to leave this small rewriting to the user rather than introduce a very weird unsoundness. 最好将这种小的重写留给用户,而不是引入非常奇怪的声音。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.