【问题标题】:In Scala how do I define upper type bounds that are exclusive of the defined class?在 Scala 中,如何定义不包含已定义类的类型上限?
【发布时间】:2018-02-04 00:13:07
【问题描述】:

给定一个具体的类Animal,我如何定义一个只接受Animal的子类的函数?

在像这样的典型示例中,Animal 是一个特征,因此定义 [A <: Animal] 意味着您已经传入了 Animal 的子类。但是,在下面这样的场景中,Animal 是具体的,我可以将其排除为允许的类型吗?

我正在使用现有的生成代码,这只是问题的一般示例。因此,这意味着我不能将Animal(或等效项)变成trait

示例如下:

class Animal {
  def name: String = "General Animal"
}

class Dog extends Animal {
  override def name: String = "Dog"
}

// How do I limit A to be a subtype of Animal (excluding Animal itself)?
class SpecificAnimalContainer[A <: Animal](a: A) {
  def specificAnimal: A = a
}

val dogContainer = new SpecificAnimalContainer[Dog](new Dog)

// I do not want this to be able to compile.
val animalContainer = new SpecificAnimalContainer[Animal](new Animal)

【问题讨论】:

  • 将动物设为trait。那么你就不能实例化Animal。问题解决了。实际上,没有动物,只有狗和猫等等。
  • @ziggystar 嗯?是什么阻碍了你实例化一个特征? o_o?你每天都在实例化Function[X, Y] 千次......
  • @ziggystar 我提到“我正在使用现有的生成代码”,因此我不能将Animal 变成特征
  • “我不能把 Animal 变成一个 trait”绝不是从“我正在使用现有的生成代码”中得出的,因为“生成的代码”可能意味着任何东西。是你制造的吗?然后调整生成器。或者在您的构建中添加一些生成后预编译过程源步骤。这是一个完全不同的问题。并且至少有两个人认为您可以随意声明您的类型(例如,作为一种特征),所以我不明白为什么我的回答值得一票。我不喜欢因为无法赶上移动目标问题而被否决,抱歉。
  • 对不起,如果问题令人困惑。这就是我添加说明的原因。我很高兴接受不同的回应,即使这只是解释为什么在 Scala 中这可能是不可能的。公平地说,你仍然没有直接回答这个问题。虽然您的解决方案无法实例化 Animal 类,但它并没有具体向我展示如何使用一种只接受 Animal 的严格子类型(不包括 Animal 本身)的方法。

标签: scala types


【解决方案1】:

使用 shapeless 你可以写:

import shapeless._

class SpecificAnimalContainer[A <: Animal](a: A)(implicit ev: A =:!= Animal) {
  def specificAnimal: A = a
}

//  val animalContainer = new SpecificAnimalContainer[Animal](new Animal)// doesn't compile

否则你可以自己实现类似的隐式类型。

Type constraint for type inequality in scala

Enforce type difference

How can I have a negation type in Scala?

【讨论】:

    【解决方案2】:

    有点不清楚您想要实现什么,但您的问题看起来与 Scala 文档中的书籍示例完全相同 https://docs.scala-lang.org/tour/upper-type-bounds.html

    abstract class Pet extends Animal {}
    
    class PetContainer[P <: Pet](p: P) {
      def pet: P = p
    }
    
    class Lion extends Animal {
      override def name: String = "Lion"
    }
    
    //  val lionContainer = new PetContainer[Lion](new Lion)
    //                         ^this would not compile
    

    希望对你有帮助

    【讨论】:

    • 也许这个答案作为评论会更好。是的,我的代码是在那之后建模的,但是有一个很大的不同。我在上限中使用的类型不是abstract,我想确保不能传入它的任何实例。在我的示例中,关键是“如何将 A 限制为动物(不包括动物本身)?”但是,@Dmytro 的另一个答案似乎回答了这个问题。
    猜你喜欢
    • 1970-01-01
    • 2018-10-05
    • 2013-06-16
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多