是否可以使用一个类型绑定的泛型方法,该类型绑定等于此特征的每个可能的具体子类,而不是特征本身?"
例如,假设我有以下继承层次结构:
sealed trait Fruit
case class Apple() extends Fruit
case class Orange() extends Fruit
...
case class Watermelon() extends Fruit
我想定义一个方法def eatFruit[T <: ???](fruit: Seq[T])
,它允许T
属于Apple
,Orange
,Watermelon
等类型但不属于类型Fruit
。绑定类型[T <: Fruit]
显然无法完成工作。
最初的推动力是我们有一个FruitRepository
类,允许不同水果的批量/批量插入。批处理是在类外部完成的,所以目前它有很多方法,包括很多重复的逻辑,包括创建批处理的saveApples(apples: Seq[Apple])
,saveOranges(oranges: Seq[Orange])
等等。更新声明。我想以更通用的方式管理此问题,但任何方法saveFruit(fruit: Seq[Fruit])
都可以允许包含苹果和橙子的列表,存储库无法处理。
...我也承认,我现在一般都很好奇这种类型绑定是否可行,即使我们最终以不同的方式解决了存储库问题。
答案 0 :(得分:2)
我们可以将上限指令与类型不等式的自定义隐式执行相结合。 Taken from here(或通常见Enforce type difference):
@annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.")
trait =!=[A, B]
object =!= {
class Impl[A, B]
object Impl {
implicit def neq[A, B] : A Impl B = null
implicit def neqAmbig1[A] : A Impl A = null
implicit def neqAmbig2[A] : A Impl A = null
}
implicit def foo[A, B](implicit e: A Impl B): A =!= B = null
}
然后我们这样做:
def eatFruit[T <: Fruit](implicit ev: T =!= Fruit) = ???
当我们称之为:
def main(args: Array[String]): Unit = {
eatFruit[Fruit]
}
我们得到:
Error:(29, 13) Cannot prove that yuval.tests.FooBar.Fruit =!= yuval.tests.FooBar.Fruit.
eatFruit[Fruit]
但这会编译:
eatFruit[Orange]
这里所有的魔力都是由于在[A, A]
对的范围内造成了隐含的模糊性,因此编译器会抱怨。
我们还可以更进一步,并实现我们自己的逻辑类型,例如,让我们称之为=<:=!=
。我们可以稍微改变以前的实现:
@annotation.implicitNotFound(msg = "Cannot prove that ${A} =<:=!= ${B}.")
trait =<:=!=[A,B]
object =<:=!= {
class Impl[A, B]
object Impl {
implicit def subtypeneq[B, A <: B] : A Impl B = null
implicit def subneqAmbig1[A] : A Impl A = null
implicit def subneqAmbig2[A] : A Impl A = null
}
implicit def foo[A, B](implicit e: A Impl B): A =<:=!= B = null
}
现在:
case class Blue()
def main(args: Array[String]): Unit = {
eatFruit[Fruit] // Doesn't compile
eatFruit[Blue] // Doesn't compile
eatFruit[Orange] // Compiles
}