Scala:涉及有界类型的内部类型的构造函数参数

时间:2011-05-07 08:32:07

标签: scala

在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。谁能解释一下这里发生了什么?

1 个答案:

答案 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"))