有人可以解释为什么r1类型是:(String => String, String)
但是r2类型是String => (String, String)
?谢谢。
def f1(n: String, m: String): String = m + n
val f2: String => String = f1(_, "something")
val r1: (String => String, String) = f2 -> "foo"
val r2: String => (String, String) = f1(_, "something") -> "foo"
答案 0 :(得分:3)
让我们看看匿名函数的place holder语法会发生什么:
val f2: String => String = f1(_, "something")
它扩展为:(x$1: String) => f1(x$1, "something")"
(使用scala -Xprint:typer
开始您的repl)
使用f2 -> "foo"
,它只会变为(f2,"foo")
,因此(String => String, String)
使用f1(_, "something") -> "foo"
,评估为:
(x:String) => f1(x,"something") -> foo
(x:String) => (f1(x,"something") , foo)
(String => (String, String))
如果首先评估占位符为何被混淆了?
评估占位符,并在编译时调整树。与->
一样,由于ArrayAssoc隐式,它在运行时被评估为元组a。
答案 1 :(得分:0)
即使在阅读了贾丁的回答之后,某些事情让我感到困惑。经过一些进一步的研究,这是我的发现。注意,为了节省输入,我没有在左侧使用Type ascriptions,让Scala推断出来。
def f1(n: String, m: String): String = m + n
// f1: (n: String, m: String)String
val f2 = f1(_, "something")
一般来说,在"表达式中强调下来"表示由编译器适当扩展的匿名函数。如果编译器找不到合适类型的'下划线'参数,它会抱怨如下:
// <console>:12: error: missing parameter type for expanded function ((x$1) => f1(x$1, "something"))
val f2 = f1(_:String, "something") // Specifiying the type of the `_` as `_:String` fixes the missing parameter type error above.
// f2: String => String = <function1>
val r1 = f2 -> "foo"
// r1: (String => String, String) = (<function1>,foo)
现在重要的东西。为什么下面的行没有给出与上面的r1相同的结果!原因在于Daniel在underscore scoping rules.
的出色回答val r2 = f1(_:String, "something") -> "foo"
// r2: String => (String, String) = <function1>
根据Daniel回答的第一条规则,匿名函数的范围将包括整个右侧表达式。所以上面扩展的匿名函数将是
(x:String) => f1(x:String, "something") -> "foo"
其中给出了函数签名String =&gt; (String,String)
为了解决这个问题,我们在Sobral的答案中使用了第二条规则,并通过用{)括起_
表达式来限制绑定到f1
的匿名函数的范围。 {},如下所示:
val r3 = (f1(_:String, "something")) -> "foo"
r3: (String => String, String) = (<function1>,foo)
现在,我们得到与val r1 = f2 -> "foo"