隐式方法参数解析?斯卡拉编译器?
Implicit methods argument resolution? Scala compiler?
我正在 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)
为什么隐式函数稍后会被脱糖?或者它是如何工作的?
隐式不是 "desugared"。 "desugar" 一词源于表达式 "syntactic sugar"。注意 "syntactic sugar" 中的 "syntactic" 部分。这意味着这种转换可以发生在非常低的句法层面。比如为了脱糖
val Ext(i) = ten
变成类似
的东西
val i = Ext.unapply(ten).get
您不必了解 Ext
、ten
或 i
的类型。您甚至根本不必知道这些符号是否存在于范围内。您获取原始句法片段,然后稍微重新排序,仅此而已。
(我添加了 get
因为否则类型不匹配,scala -print
打印的实际脱糖代码更加可怕)
implicit
的搜索非常不同。它关键取决于以下事实:所有符号和方法签名都已解析,并且所有子表达式的所有类型都已派生 [脚注 1]。这是因为:
- 必须解析符号,否则编译器甚至不知道对象
Ext
上的方法 unapply
需要额外的隐式参数。
- 必须知道类型,否则它不知道要搜索什么类型的隐式。
这两种信息都不存在于程序的原始句法结构中,必须在后期阶段首先重构。这就是为什么隐式解析必须在纯句法脱糖之后。
[脚注 1] 过于简单化了:类型检查器必须在插入一些隐式后以某种方式推断出更多信息,因此这些阶段似乎必须交织在一起。
我正在 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)
为什么隐式函数稍后会被脱糖?或者它是如何工作的?
隐式不是 "desugared"。 "desugar" 一词源于表达式 "syntactic sugar"。注意 "syntactic sugar" 中的 "syntactic" 部分。这意味着这种转换可以发生在非常低的句法层面。比如为了脱糖
val Ext(i) = ten
变成类似
的东西val i = Ext.unapply(ten).get
您不必了解 Ext
、ten
或 i
的类型。您甚至根本不必知道这些符号是否存在于范围内。您获取原始句法片段,然后稍微重新排序,仅此而已。
(我添加了 get
因为否则类型不匹配,scala -print
打印的实际脱糖代码更加可怕)
implicit
的搜索非常不同。它关键取决于以下事实:所有符号和方法签名都已解析,并且所有子表达式的所有类型都已派生 [脚注 1]。这是因为:
- 必须解析符号,否则编译器甚至不知道对象
Ext
上的方法unapply
需要额外的隐式参数。 - 必须知道类型,否则它不知道要搜索什么类型的隐式。
这两种信息都不存在于程序的原始句法结构中,必须在后期阶段首先重构。这就是为什么隐式解析必须在纯句法脱糖之后。
[脚注 1] 过于简单化了:类型检查器必须在插入一些隐式后以某种方式推断出更多信息,因此这些阶段似乎必须交织在一起。