带有implicits的Scala键入会给出输入错误

时间:2012-10-18 06:32:42

标签: scala

我正在努力实现这个:

def buildQuery() {
  val restrictions: ConjunctionRestriction[String, Int] =
    ("name" is "Some One") and ("age" is 20)
}

implicit def stringToEqualsRestrictionBuilder[T](fieldName: String)
                                                : EqualsRestrictionBuilder[T] =
  new EqualsRestrictionBuilder[T](fieldName)

implicit def restrictionToConjunctionBuilder[L,R](restriction: Restriction[L])
                                                 : ConjunctionBuilder[L,R] =
  new ConjunctionBuilder[L,R](restriction)

case class Restrictions(restrictions: Restriction[_]*)

trait Restriction[T] {
  def toString: String
}

class EqualsRestriction[T](val fieldName: String, val value: T)
    extends Restriction[T] {
  override def toString = fieldName + "=" + value
}

class ConjunctionRestriction[A,B](val lhs: Restriction[A],
                                  val rhs: Restriction[B]) 
    extends Restriction[(A,B)] {
  override def toString = "(" + lhs + ") AND (" + rhs + ")"
}

class EqualsRestrictionBuilder[T](val fieldName: String,
                                  val restriction: Option[Restriction[T]] = None) {

  def is(value: Int) =
    new EqualsRestriction[Int](fieldName, value)

  def is(value: String) =
    new EqualsRestriction[String](fieldName, "\"" + value + "\"")
}

class ConjunctionBuilder[L,R](val lhs: Restriction[L]) {
  def and(rhs: Restriction[R]) = new ConjunctionRestriction[L,R](lhs, rhs)
}

编译器给我错误:

error: type mismatch;
found   : MyOuterClass.this.EqualsRestriction[Int]
required: MyOuterClass.this.Restriction[R]
val restrictions: ConjunctionRestriction[String, Int] =
  ("name" is "Some One") and ("age" is 20)

我没有想到scala类型系统。这有什么问题?

由于

修改

通过将ConjunctionBuilder更改为只有一个参数类型L来修复:

class ConjunctionBuilder[L](val lhs: Restriction[L]) {
  def and[R](rhs: Restriction[R]) = new ConjunctionRestriction[L,R](lhs, rhs)
}

implicit def restrictionToConjunctionBuilder[L](restriction: Restriction[L])
                                               : ConjunctionBuilder[L] =
  new ConjunctionBuilder[L](restriction)

但有人可以解释为什么使用R参数类型,编译失败了吗?

1 个答案:

答案 0 :(得分:3)

ConjunctionBuilder具有R类型参数时,它失败,因为在应用隐式转换restrictionToConjunctionBuilder时,编译器只能推断L(来自参数{{1} }})。 类型参数restriction不会出现在参数列表中的任何位置,因此无法推断它。 当无法推断出类型参数时,你来显式传递它们(当然,在隐式转换的情况下,这会使目的失败)。 例如:以下编译正确:

R

如果没有明确指定类型参数,编译器就无法绑定val restrictions: ConjunctionRestriction[String, Int] = (("name" is "Some One"): ConjunctionBuilder[String, Int]) and ("age" is 20) ,因此无法证明方法R的参数是正确的类型。 实际上,该方法需要and,我们给它Restriction[R]。这只能匹配Restriction[Int] == R,编译器无法证明Int未绑定。

您的修复完全正确:将类型参数R移至R的定义。这种方式在应用隐式转换and时,编译器可以从参数restrictionToConjunctionBuilder完全推断出所有类型参数(即uniqye类型参数L)。 然后,在应用restriction时,它可以从其参数and

推断R