通用协变量类带有上类型边界缺点

发布于 2025-01-23 13:10:24 字数 2872 浏览 2 评论 0原文

Scala建议在通用类中使用协方差解决方案[+T]解决方差问题,当我深入研究时,我可以产生两种解决方案,事实是,每个解决方案都有其自己的劣势。

解决方案1-例如,在类标头和方法中使用上层类型边界。

class Animal(val name: String)
class Dog(override val name: String, val property: String) extends Animal(name)
class Puppy(override val name: String, override val property: String, val age: Int) extends Dog(name, property)
 
 
abstract class AnimalCage[+A <: Animal] {
  def head: A
  def tail: AnimalCage[A]
  def add[A <: Animal](animal: A): AnimalCage[Animal]
}
 
class RealCage[+A <: Animal](h: A, t: AnimalCage[A]) extends AnimalCage[A] {
  override def head: A = h
  override def tail: AnimalCage[A] = t
  override def add[A <: Animal](animal: A): AnimalCage[Animal] = new RealCage(animal, this)
}
 
object EmptyCage extends AnimalCage[Nothing] {
  override def head: Nothing = throw new NoSuchElementException()
  override def tail: AnimalCage[Nothing] = throw new NoSuchElementException()
  override def add[A <: Animal](animal: A): AnimalCage[Animal] = new RealCage(animal, this)
}
 
  val dog1: Dog = new Dog("dog_1", "bark bark")
  val dogCage: RealCage[Dog] = new RealCage(dog1, EmptyCage)
  val puppy1: Puppy = new Puppy("puppy_1", "puppy bark", 5)
 
 
  val x: AnimalCage[Dog] = dogCage.add(puppy1) //error! must be Animal, could not be Dog!

优点 - [动物]是更高的超级式笼子可以保持

缺点 - 当我将[Puppy]([狗]的子类型)添加到[狗]的笼子中时,我不能有[狗]的笼子而是[动物]的笼子。

解决方案2-仅在方法签名

abstract class AnyCage[+A] {
  def head: A
  def tail: AnyCage[A]
  def add[B >: A](animal: B): AnyCage[B]
}
 
class RealCage[+A](h: A, t: AnyCage[A]) extends AnyCage[A] {
  override def head: A = h
  override def tail: AnyCage[A] = t
  override def add[B >: A](animal: B): AnyCage[B] = new RealCage(animal, this)
}
 
object EmptyCage extends AnyCage[Nothing] {
  override def head: Nothing = throw new NoSuchElementException()
  override def tail: AnyCage[Nothing] = throw new NoSuchElementException()
  override def add[B >: Nothing](animal: B): AnyCage[B] = new RealCage(animal, this)
}
 
  val dog1: Dog = new Dog("dog_2", "bark bark")
  val dogCage: AnyCage[Dog] = new RealCage(dog1, EmptyCage)
 
  val bug: LivingCreature = new LivingCreature("bug")
  val generalCage: AnyCage[Any] = dogCage.add(bug) // compiled but we lose all properties due to the fact the [Any] is lowest super-type.

专业人士中使用边界 - 当我将[puppy]([狗]的子类型)添加到[狗]的笼子中时,我会得到[狗]的笼子,而不是[动物]以前的解决方案。

缺点 - 我们对任何挂盘没有限制[+a],即使它与动物无关,我们也可以添加任何类型,然后较低的超级型将导致我们失去所有的所有类型[动物]的特性。

因此,问题是,是否有任何方法可以将上述两个解决方案结合起来,然后做类似的事情 -

  abstract class AnimalCage[+A <: Animal] {
    def head: A
    def tail: AnimalCage[A]
    override def add[A <: B <: Animal](animal: B): AnimalCage[B] = new RealCage(animal, this)
  }

即,当我们俩都可以对笼子(&lt;:andial)限制并获得最低的超级型(不是[动物) ]但是[狗])在一种情况下,我们想在[狗]的笼子中添加一个[小狗]。

谢谢

Scala suggests using the covariance solution [+T] for the variance problem in generic class, and when I dig into it I could produce two solutions, the thing is that each one of them has its own disadvantage.

Solution 1 - using upper type boundary both in the class header and in the method, for example.

class Animal(val name: String)
class Dog(override val name: String, val property: String) extends Animal(name)
class Puppy(override val name: String, override val property: String, val age: Int) extends Dog(name, property)
 
 
abstract class AnimalCage[+A <: Animal] {
  def head: A
  def tail: AnimalCage[A]
  def add[A <: Animal](animal: A): AnimalCage[Animal]
}
 
class RealCage[+A <: Animal](h: A, t: AnimalCage[A]) extends AnimalCage[A] {
  override def head: A = h
  override def tail: AnimalCage[A] = t
  override def add[A <: Animal](animal: A): AnimalCage[Animal] = new RealCage(animal, this)
}
 
object EmptyCage extends AnimalCage[Nothing] {
  override def head: Nothing = throw new NoSuchElementException()
  override def tail: AnimalCage[Nothing] = throw new NoSuchElementException()
  override def add[A <: Animal](animal: A): AnimalCage[Animal] = new RealCage(animal, this)
}
 
  val dog1: Dog = new Dog("dog_1", "bark bark")
  val dogCage: RealCage[Dog] = new RealCage(dog1, EmptyCage)
  val puppy1: Puppy = new Puppy("puppy_1", "puppy bark", 5)
 
 
  val x: AnimalCage[Dog] = dogCage.add(puppy1) //error! must be Animal, could not be Dog!

pros - [Animal] is the higher super-class Cage can holds

cons - When I'm adding [Puppy] (sub-type of [Dog]) to a Cage of [Dog] I can't have Cage of [Dog] but rather Cage of [Animal].

solution 2 - using boundary only in method signature

abstract class AnyCage[+A] {
  def head: A
  def tail: AnyCage[A]
  def add[B >: A](animal: B): AnyCage[B]
}
 
class RealCage[+A](h: A, t: AnyCage[A]) extends AnyCage[A] {
  override def head: A = h
  override def tail: AnyCage[A] = t
  override def add[B >: A](animal: B): AnyCage[B] = new RealCage(animal, this)
}
 
object EmptyCage extends AnyCage[Nothing] {
  override def head: Nothing = throw new NoSuchElementException()
  override def tail: AnyCage[Nothing] = throw new NoSuchElementException()
  override def add[B >: Nothing](animal: B): AnyCage[B] = new RealCage(animal, this)
}
 
  val dog1: Dog = new Dog("dog_2", "bark bark")
  val dogCage: AnyCage[Dog] = new RealCage(dog1, EmptyCage)
 
  val bug: LivingCreature = new LivingCreature("bug")
  val generalCage: AnyCage[Any] = dogCage.add(bug) // compiled but we lose all properties due to the fact the [Any] is lowest super-type.

pros - When I'm adding [Puppy] (sub-type of [Dog]) to a Cage of [Dog], I get Cage of [Dog] and not [Animal] like the previous solution.

cons - we don't have restrictions on AnyCage[+A] and we can potentially add any type, even if it's not related to Animal, and then the lower super-type would be [Any] which will cause us to lose all the properties of [Animal].

Therefore, the question is, if there is any way to combine the above two solution and do something like -

  abstract class AnimalCage[+A <: Animal] {
    def head: A
    def tail: AnimalCage[A]
    override def add[A <: B <: Animal](animal: B): AnimalCage[B] = new RealCage(animal, this)
  }

i.e, when we both can have restrictions on Cage (<: Animal) and also receive the lowest super-type (not [Animal] but [Dog]) in a case we want to add a [Puppy] to a Cage of [Dog].

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瞳孔里扚悲伤 2025-01-30 13:10:24

这两个都会做 -

  class LivingCreature(val name: String)
  class Animal(val name: String)
  class Cat(override val name: String, val property: String) extends Animal(name)
  class Dog(override val name: String, val property: String) extends Animal(name)
  class Puppy(override val name: String, override val property: String, val age: Int) extends Dog(name, property)


  abstract class Cage[+A <: Animal] {
    // without explicitly point into my own class `<: Animal` in the class signature
    // the upper border would be [Any]
    def head: A
    def tail: Cage[A]
    def add[B >: A <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
    // [A <: Animal] - means [Animal] is super-type of [A].
  }

  class RealCage[+A <: Animal](h: A, t: Cage[A]) extends Cage[A] {
    override def head: A = h
    override def tail: Cage[A] = t
    override def add[B >: A <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
  }

  object EmptyCage extends Cage[Nothing] {
    override def head: Nothing = throw new NoSuchElementException()
    override def tail: Cage[Nothing] = throw new NoSuchElementException()
    override def add[B >: Nothing <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
  }

  val dog: Dog = new Dog("my_dog", "bark bark")
  val dogCage_1: Cage[Dog] = new RealCage(dog, EmptyCage)
  val puppy: Puppy = new Puppy("my_puppy", "puppy bark", 5)
  val dogCage_2:  Cage[Dog] = dogCage_1.add(puppy) // keeps Dog Cage

  val cat: Cat = new Cat("my_cat", "miau")
  val animalCage: Cage[Animal] = dogCage_2.add(cat)

  val bug: LivingCreature = new LivingCreature("my_bug")
  val x: Cage[LivingCreature] = animalCage.add(bug) // doesn't compile as expected

谢谢路易斯

That'll do them both -

  class LivingCreature(val name: String)
  class Animal(val name: String)
  class Cat(override val name: String, val property: String) extends Animal(name)
  class Dog(override val name: String, val property: String) extends Animal(name)
  class Puppy(override val name: String, override val property: String, val age: Int) extends Dog(name, property)


  abstract class Cage[+A <: Animal] {
    // without explicitly point into my own class `<: Animal` in the class signature
    // the upper border would be [Any]
    def head: A
    def tail: Cage[A]
    def add[B >: A <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
    // [A <: Animal] - means [Animal] is super-type of [A].
  }

  class RealCage[+A <: Animal](h: A, t: Cage[A]) extends Cage[A] {
    override def head: A = h
    override def tail: Cage[A] = t
    override def add[B >: A <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
  }

  object EmptyCage extends Cage[Nothing] {
    override def head: Nothing = throw new NoSuchElementException()
    override def tail: Cage[Nothing] = throw new NoSuchElementException()
    override def add[B >: Nothing <: Animal](animal: B): Cage[B] = new RealCage(animal, this)
  }

  val dog: Dog = new Dog("my_dog", "bark bark")
  val dogCage_1: Cage[Dog] = new RealCage(dog, EmptyCage)
  val puppy: Puppy = new Puppy("my_puppy", "puppy bark", 5)
  val dogCage_2:  Cage[Dog] = dogCage_1.add(puppy) // keeps Dog Cage

  val cat: Cat = new Cat("my_cat", "miau")
  val animalCage: Cage[Animal] = dogCage_2.add(cat)

  val bug: LivingCreature = new LivingCreature("my_bug")
  val x: Cage[LivingCreature] = animalCage.add(bug) // doesn't compile as expected

Thanks Luis

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文