4

在 scala 中,有一些按名称调用的参数:

def hello(who: => String) = println("hello, " + who)

参数的类型是who什么?

它将scala REPL上的功能显示为:

hello: (who: => String)Unit

类型还在=> String吗?它有什么名字吗?或者一些描述类型的文档?

回答提出的进一步问题

问题 1

(阅读§3.3.1(MethodTypes)的规范时)

方法类型是方法的类型,比如说我定义了一个方法hello

def hello: String = "abc"

它的类型可以写成:=> String,对吧?虽然您可以看到 REPL 响应是:

scala> def hello:String = "abc"
hello: String

如果我定义一个有参数的方法:

def goodname(name: String): String = name + "!"

方法的类型是什么?它应该类似于String => String,但不是。因为它是一个方法类型,而且String => String是一个函数类型。

问题2

(阅读§3.3.1(MethodTypes)的规范时)

我可以这样理解:

def goodname(name: String): String = name + "!"
def print(f: String => String) = println(f("abc"))
print(goodname)

当我调用print(goodname)时,类型goodname将转换为函数类型String => String,对吗?

但是对于无参数方法:

def hello: String = "abc"

可以转换什么函数类型?我试过了:

def print(f: () => String) = println(f())

但这不能编译:

print(hello)

错误是:

错误:类型不匹配;发现:需要字符串:()=>字符串

你能给我一个有效的例子吗?

问题 3

(阅读 §6.26.2 (MethodConversions) 的规范时)

评估转换仅在类型未应用于参数时发生。所以,对于代码:

def myname:String = "abc"
def print(name: => String) = println(name)
print(myname)

我的问题是,当我打电话时print(myname),是否发生了转换(我的意思是Evaluation conversion)?我猜,由于类型myname是 just => String,所以可以直接传递给print

如果print方法发生了变化:

def myname:String = "abc"
def print(name: String) = println(name)
print(myname)

这里Evaluation conversion肯定发生了,对吧?(从=> StringString

4

1 回答 1

7

引用规范的§4.6.1

这种参数的类型就是无参数方法类型=> T

因此,按名称调用参数的类型是(大约)() => T(或者Function0[T]如果您愿意)。如果您:javap的方法接受名称调用参数,您将看到编译后的代码接受 type 的参数scala.Function0<java.lang.Object>

一个近似的例子

译文:

def callByName[T](f: => T) = f

callByName { /* magic */
    1 + 1
/* ends here */ }

有效地:

def callByName[T](f: Function0[T]) = f.apply()

callByName(new Function0[Int] {
  def apply() = { /* magic */
    1 + 1
  /* ends here */ }
})

对近似值的怀疑

您可能很想尝试将 a 传递() => T给您的方法。试试callByName(() => 12);为什么它不编译?(提示,考虑调用站点的扩展)。(将鼠标悬停在以下空白处以查看答案):

无法编译的原因callByName(() => 12)是因为扩展被视为: callByName(new Function0[() => Int] { def apply() = () => 12 }) 也就是说,而不是传入 a Function0which return an Intyou are传入 a Function0which 返回 a Function0which 返回 a Int

=> T实际上是什么

=> T实际上是方法类型,而不是对象。因此,之前的所有内容都是编译器所做工作的近似值,并且可以随时更改。引用§3.3

下面解释的类型不表示值的集合,它们也没有显式地出现在程序中。它们在本报告中作为已定义标识符的内部类型进行介绍。

那么什么是方法类型呢?引用§3.3.1 (MethodTypes)

一种特殊情况是没有任何参数的方法类型。他们写在这里=> T。每次引用无参数方法名称时都会重新计算的无参数方法名称表达式。

方法类型不作为值的类型存在。如果将方法名称用作值,则其类型会隐式转换为相应的函数类型(第 6.26 节)。

§6.26.3 (MethodConversions)规定:

以下四种隐式转换可以应用于未应用于某些参数列表的方法。

评估。m类型的无参数方法=> T总是通过计算绑定T的表达式转换为类型。m

所以类型的正确翻译=> T总是:

def random$name$here: T

例子

这是一个可以玩的示例类:

class TestParamless {
  def paramless: Int = 1
  def callByName(f: => Int) = f
  def example: Int = callByName(paramless)
}

new TestParamless().example也尝试一下:javap TestParamless(在 scala REPL 中)。

于 2014-08-20T15:58:54.270 回答