【问题标题】:How to restrict generic trait in subtype如何限制子类型中的通用特征
【发布时间】:2023-02-06 04:28:36
【问题描述】:

我有一个特征 Mutable[T],它描述了可以使用 Mutation 对象突变为 T 的对象:

trait Mutable[T] {
  def mutate(mutation: Mutation): T
}

class Mutation {
  def perform[T <: Mutable[T]](mutable: T): T = mutable.mutate(this)
}

我还有两个描述一般动物和特定哺乳动物的特征。

我想要求 Animal 可以变异为另一个 Animal,但 Mammal 只能变异为另一个 Mammal。但是,以下内容不会编译:

trait Animal extends Mutable[Animal]
trait Mammal extends Animal, Mutable[Mammal]

case class Fish() extends Animal {
  override def mutate(mutation: Mutation): Animal = Fish()
}

// error: class Monkey cannot be instantiated since it has conflicting base types Mutable[Animal] and Mutable[Mammal]
case class Monkey() extends Mammal {
  override def mutate(mutation: Mutation): Mammal = Monkey()
}

我想按如下方式使用这些类型:

val mutation = new Mutation()

val fish: Animal = Fish()
val fish2: Animal = mutation.perform(fish)

val monkey: Mammal = Monkey()
val monkey2: Mammal = mutation.perform(monkey)

【问题讨论】:

    标签: scala generics traits


    【解决方案1】:

    该错误是由Monkey 的超类型列表中的Mutable[Animal]Mutable[Mammal] 之间的冲突引起的。

    要解决冲突,您可以改用与Mutable[Mammal]兼容的Mutable[? &lt;: Animal]

    trait Animal extends Mutable[? <: Animal]
    trait Mammal extends Animal, Mutable[Mammal]
    

    然后,要扩展类型 Animal,您必须显式添加 Mutable[Animal] 作为超类型才能覆盖 mutate 方法:

    case class Fish() extends Animal, Mutable[Animal] {
      override def mutate(mutation: Mutation): Animal = Fish()
    }
    

    定义辅助特性以节省一些输入可能会有所帮助:

    trait AnimalBase extends Animal, Mutable[Animal]
    case class Fish() extends AnimalBase {
      override def mutate(mutation: Mutation): Animal = Fish()
    }
    

    但是,Animal 的类型现在不再符合 Mutation.perform 的要求,即使您显式指定了类型参数:

    val mutation = new Mutation()
    
    val monkey: Mammal = Monkey()
    val monkey2: Mammal = mutation.perform(monkey)  // OK
    val monkey3: Mammal = mutation.perform[Mammal](monkey)  // OK
    
    val fish: Animal = Fish()
    val fish2: Animal = mutation.perform(fish)  // error: Found: (fish : Animal), Required: Nothing
    val fish3: Animal = mutation.perform[Animal](fish)  // error: Type argument Animal does not conform to upper bound Mutable[Animal]
    

    这可以通过放宽对 Mutation.mutate[T &lt;: Mutable[? &lt;: T]] 的限制来解决:

    class Mutation {
      def perform[T <: Mutable[? <: T]](mutable: T): T = mutable.mutate(this)
    }
    
    val mutation = new Mutation()
    
    val fish: Animal = Fish()
    val fish2: Animal = mutation.perform(fish)  // OK
    val fish3: Animal = mutation.perform[Animal](fish)  // OK
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 2015-03-30
      • 1970-01-01
      • 2015-09-19
      • 2021-11-16
      相关资源
      最近更新 更多