2

我正在尝试实现这一点:

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 参数类型编译失败吗?

4

1 回答 1

3

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

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

由于没有明确指定类型参数,编译器无法 bind R,因此无法证明方法的参数and是正确的类型。实际上,该方法需要 a Restriction[R],我们给它 a Restriction[Int]。这只能匹配 if R== Int,编译器无法证明它R是未绑定的。

您的修复是完全正确的:将类型参数移动Rand. 这样在应用隐式转换restrictionToConjunctionBuilder时,编译器可以从 parameter 中完全推断出所有类型参数(即 uniqye 类型参数Lrestriction。然后,在应用时可以从其参数and推断Rrhs

于 2012-10-18T08:38:33.247 回答