简体   繁体   English

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

[英]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 : 只要它们不是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

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. valvar参数不能按名称命名的原因很简单,就是就此而言,类字段不能按名称命名,只能是局部变量。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM