我正在努力实现这个:
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参数类型,编译失败了吗?
答案 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