在scala 2.9.0.RC3中,我定义了解析器的特征和解析器的具体示例:
trait Parser {
type Result
def parse(s: String): Result
}
class IdParser extends Parser {
case class Result(s: String)
def parse(s: String) = new Result(s)
}
现在我希望能够比较解析后的值:
class Comparator[P <: Parser](p: P) {
def compare(s1: String, s2: String) = p.parse(s1) == p.parse(s2)
}
这很好,我可以做到:
println(new Comparator(new IdParser).compare("a", "b"))
按预期生成 false 。不幸的是,它从这里开始走下坡路。为了进行更高级的比较,我定义:
class CustomisableComparator[P <: Parser](p: P,
cmp: (P#Result, P#Result) => Boolean = (r1: P#Result, r2: P#Result) => r1 == r2) {
def compare(s1: String, s2: String) = cmp(p.parse(s1), p.parse(s2))
}
并尝试像以前一样调用它:
println(new CustomisableComparator(new IdParser).compare("a", "b"))
但是:
error: type mismatch; found : (this.Parser#Result, this.Parser#Result) => Boolean required: (this.IdParser#Result, this.IdParser#Result) => Boolean Error occurred in an application involving default arguments. println(new CustomisableComparator(new IdParser).compare("a", "b")) ^
哦,好吧,我希望P
中的类型变量CustomisableComparator
绑定到IdParser
,所以我不太清楚为什么scala认为它是Parser
在默认值中。让我们忘记默认值然后明确提供值:
println(new CustomisableComparator(new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
error: type mismatch; found : (this.IdParser#Result, this.IdParser#Result) => Boolean required: (?#Result, ?#Result) => Boolean println(new CustomisableComparator(new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b")) ^
这很令人困惑。如果我没有提供值,编译器会期望(this.IdParser#Result, this.IdParser#Result) => Boolean
;一旦我提供了这种类型的值,它就会(?#Result, ?#Result) => Boolean
。谁能解释一下这里发生了什么?
答案 0 :(得分:4)
你只是要求过多的类型推断。你似乎认为它会为你回溯,但事实并非如此。
如果您提供类型,则两个示例都会编译:
println(new CustomisableComparator[Parser](new IdParser).compare("a", "b"))
println(new CustomisableComparator[IdParser](new IdParser, (r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))
或者,如果您在战略位置使用其他参数列表,您将在这些情况下(从左到右)获得更好的类型推断。
class CustomisableComparator2[P <: Parser](p: P)(cmp: (P#Result, P#Result) => Boolean = ((x: P#Result, y: P#Result) => x == y)) {
def compare(s1: String, s2: String) = cmp(p.parse(s1), p.parse(s2))
}
// type parameter successfully inferred
println(new CustomisableComparator2(new IdParser)((r1: IdParser#Result, r2: IdParser#Result) => r1 == r2).compare("a", "b"))