【问题标题】:Scala generics in an abstract function抽象函数中的 Scala 泛型
【发布时间】:2015-04-21 07:24:06
【问题描述】:

有一个抽象类AnimalAnimalDogCow 扩展。 Animal 有一个抽象函数 copy。在Dog 上调用时应返回Dog,在Cow 上调用时应返回Cow

abstract class Animal[T] {
  def copy[CT <: Animal[T]] (): CT
}

class Dog[T] extends Animal[T] {
  def copy = new Dog[T]()
}

这给出了一个错误。我做错了什么?

【问题讨论】:

  • “这给出了一个错误。”。不要让我们猜测。给出错误。而这种情况下的错误应该会给你一个线索(因为它说来自 Animal 的副本不是由 Dog 实现的)

标签: scala generics inheritance


【解决方案1】:

Dog 中的copy 方法与Animal 中的copy 方法的签名不同(Animal 有类型参数而Dog 没有),所以 Scala 编译器认为你还没有为Dog 实现它。看起来您正在尝试解决 copy 应该返回子类型的事实。您可以为此使用自我类型:

abstract class Animal[T] { self: T =>
  def copy: T = this
}

class Dog extends Animal[Dog]

除非您对类型参数有其他想法?

在这种情况下使用 F 有界多态性可能更谨慎,以验证 TAnimal 的子类型。

abstract class Animal[T <: Animal[T]]

【讨论】:

    【解决方案2】:

    基本上CT 对于您的工作方法来说必须是不变的。您对 Dog 的具体实现无法控制 CT 的类型,例如,您的方法无法解释这一点(因此会出现编译器错误):

    new Dog[Int]().copy[Cow[Int]]()
    

    你的具体实现给了我一个Dog,但我想要一个Cow。这是因为您的 copy 方法不可能满足返回类型参数的变化。如果您只需要copy 方法的一种返回类型,您可以采用这种替代方法(灵感来自与 C++ 中发生的相同问题):

    abstract class Animal[T, SubType <: Animal[T, _]] {
      def copy (): SubType
    }
    
    class Dog[T] extends Animal[T, Dog[T]] {
      override def copy() = new Dog[T]
    }
    
    val animal: Animal[Int, Dog[Int]] = new Dog()
    val dogCopy: Dog[Int] = animal.copy()
    

    这是另一种更简单(不那么明显)的方法。 Scala 不仅允许您覆盖方法的实现,还允许在某种程度上覆盖返回类型:

    abstract class Animal[T] {
      def copy (): Animal[T]
    }
    
    class Dog[T] extends Animal[T] {
      override def copy() = new Dog[T]
    }
    
    val dog = new Dog[Int]()
    val dogCopy: Dog[Int] = dog.copy()
    

    【讨论】:

      猜你喜欢
      • 2016-09-04
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      • 2020-03-12
      相关资源
      最近更新 更多