我正在学习 Scala 中的隐式方法。例如,考虑以下测试代码:
object Test{
def main(args: Array[String]) = {
implicit val f: Int => String = (_: Int).toString + "sdgfdfsg"
val Ext(i) = 10
println(i)
}
}
object Ext{
def unapply(i: Int)(implicit f: Int => String): Option[String] = Some(f(i))
}
此代码按预期工作。但我不清楚的是它为什么有效。所以我读到了 Scala compiler phases 并发现所有脱糖都是在第一阶段进行的:
parser 1 parse source into ASTs, perform simple desugaring
但是脱糖的顺序是什么?在示例中似乎
val Ext(i) = 10
首先脱糖为
val i = Ext.unapply(10)
然后编译器找到隐式值implicit val f: Int => String = (_: Int).toString + "sdgfdfsg"
最终脱糖版本为
val i = Ext.unapply(10)(f)
为什么稍后要对隐式进行脱糖处理?或者它是如何工作的?
最佳答案
隐式并未“脱糖”。 “脱糖”一词源于“语法糖”这一表达方式。注意“语法糖”中的“语法”部分。这意味着这种转换可以发生在非常低的句法级别上。比如为了脱糖
val Ext(i) = ten
变成类似的东西
val i = Ext.unapply(ten).get
您不必了解 Ext
的类型。 ,或ten
,或i
。您甚至不必知道这些符号是否存在于作用域中。您获取原始语法片段,然后对它们进行一些重新排序,仅此而已。
(我添加了get
,因为否则类型不匹配,scala -print
打印的实际脱糖代码明显更可怕)
搜索implicit
s 是非常不同的。它关键取决于以下事实:所有符号和方法签名均已解析,并且所有子表达式的所有类型均已派生[脚注 1]。这是因为:
- 必须解析符号,否则编译器甚至不知道方法
unapply
在对象上Ext
需要额外的隐式参数。 - 类型必须已知,否则它将不知道要搜索什么类型的隐式。
这两种信息都不存在于程序的原始语法结构中,并且必须首先在后续阶段中重建。这就是为什么隐式解析必须在纯粹的语法脱糖之后进行。
[脚注 1] 这过于简单化了:在插入一些隐式后,类型检查器必须以某种方式推断出更多信息,因此这些阶段似乎必须交织在一起。
关于scala - 隐式方法参数解析? Scala 编译器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49094615/