是什么类型的`=> scala中的字符串`

时间:2014-08-20 15:50:13

标签: scala callbyname

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

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

参数who的类型是什么?

它将scala REPL上的函数显示为:

hello: (who: => String)Unit

类型是否仍为=> String?它有什么名字吗?或者一些描述类型的文档?

answer

提出的其他问题

问题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的类型只是=> String,因此可以直接传递给print

如果print方法已更改:

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

此处Evaluation conversion肯定发生了,对吗?(从=> StringString

1 个答案:

答案 0 :(得分:7)

引自§4.6.1 of the spec

  

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

因此,名称调用参数的类型是(大约)() => T(如果您愿意,可以是Function0[T])。如果你:javap接受一个call-by-name参数的方法,你会看到编译的代码接受一个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 */ }
})

怀疑围绕近似值

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

  

callByName(() => 12)无法编译的原因是因为扩展被视为:           callByName(new Function0 [()=&gt; Int] {           def apply()=()=&gt; 12         })  也就是说,而不是传入Function0,而Int返回Function0,而您传递的Function0会返回Int,返回=> T

=> T实际上是什么

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

  

以下说明的类型不表示值集,也不会在程序中明确显示。它们在本报告中作为已定义标识符的内部类型引入。

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

  

特殊情况是没有任何参数的方法类型。它们写在m。无参数方法命名每次引用无参数方法名称时重新求值的表达式。

     

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

并且§6.26.3 (MethodConversions)声明:

  

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

     

评估。类型=> 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以及{{1}}(在scala REPL中)。