【问题标题】:Using the Scala type system to flexibly assert that a base class has some combination of additional properties使用 Scala 类型系统灵活地断言基类具有某些附加属性的组合
【发布时间】:2017-10-27 17:46:22
【问题描述】:

我有一个如下所示的 scala 类:

class Zoo {
    val name: String 
    val location: String 

    val lion: Option[Object]
    val tiger: Option[Object]
    val bear: Option[Object]
}

使用 Zoo 的代码必须在运行时检查是否存在狮子、老虎和/或熊。我希望能够在编译时断言存在哪些动物。

目前我有以下内容:

class Zoo {
    val name: String
    val location: String
}

case class ZooWithBear(zoo: Zoo, bear: Bear)
case class ZooWithLion(zoo: Zoo, lion: Lion)
case class ZooWithTiger(zoo: Zoo, tiger: Tiger)

def foo(zooWithBear: ZooWithBear) : Int

当我想断言动物的组合必须存在时,这显然会失败——案例类别的数量会爆炸式增长。

我还可以使用 HasBear、HasLion 和 HasTiger 等特征。这在方法签名 (def foo(z: Zoo with HasLion)) 中效果很好,但是给定 Zoo 的实例具有一些未知的附加特征集,没有办法添加特征。 (通过某种zoo.withTiger(tiger): Self with HasTiger 类型的方法。)我必须了解动物园最初建造时的所有现有动物。

给定一个像 Zoo 这样具有公共属性的基类,我如何使用类型系统灵活地创建具有附加属性的 Zoo 实例,并在方法签名中断言传入的 Zoo 实例具有一组特定的附加属性?

【问题讨论】:

  • 考虑这种关系。动物园有动物。 Zoo 是一个类,Animal 是一个类。关键字“with”应该告诉您存在链接关系,而不是涉及“is”关系。如果这有意义吗?因此,对于这个问题,适当的操作是布尔 hasAnimal(Animal animal) 等...然后您可以让 Animal 成为每个动物类的父类。
  • @ErickStone 我知道我在以违反 OO 原则的方式滥用类型系统,但我仍然想弄清楚它是否可能:-)。 hasAnimal(Animal animal) 听起来很合理,但它只在运行时有效。我希望能够在编译时做出断言。 (例如def someMethod(zoo: Zoo with HasBear with HasTiger)

标签: scala types


【解决方案1】:

为了实现你想要的,你可以使用 mixins 并组合类型,然后先匹配组合,然后再匹配特定情况,如下所示:

class Zoo(name: String = "Madagascar", location: String = "Africa")

trait HasBear
trait HasLion
trait HasTiger

val myZoo1 = new Zoo with HasBear with HasLion with HasTiger
val myZoo2 = new Zoo with HasBear with HasLion
val myZoo3 = new Zoo with HasBear with HasTiger
val myZoo4 = new Zoo with HasLion with HasTiger
val myZoo5 = new Zoo with HasBear
val myZoo6 = new Zoo with HasLion
val myZoo7 = new Zoo with HasTiger

def foo(zoo: Zoo) : Int = {
  zoo match {
    case _: Zoo with HasBear with HasLion with HasTiger => 1
    case _: Zoo with HasBear with HasLion => 2
    case _: Zoo with HasBear with HasTiger => 3
    case _: Zoo with HasLion with HasTiger => 4
    case _: HasBear  => 5
    case _: HasLion => 6
    case _: HasTiger => 7
  }
}

foo(myZoo1)
foo(myZoo2)
foo(myZoo3)
foo(myZoo4)
foo(myZoo5)
foo(myZoo6)
foo(myZoo7)

重要提示:在匹配中,必须先添加特征多的情况,然后添加较少的情况,否则匹配将不符合预期

【讨论】:

  • 太棒了,我认为这可以实现大部分目标。我如何向 Zoo 添加一个方法,例如:def withBear(bear: Bear) : Self with HasBear?
  • @FullTimeCoderPartTimeSysAdmin 你想要那个方法在哪里?那个方法有什么作用?
  • 我的意思是,方法 foo,据我所知,正是这样做的,你看到我的更新了吗?你给它一个动物园,并在它拥有的动物的基础上归还一些东西
  • 哦,我明白了,我可以用它来建造一个具有适当特征的动物园
猜你喜欢
  • 2012-01-19
  • 1970-01-01
  • 2018-05-08
  • 2012-12-05
  • 2016-06-21
  • 2021-12-16
  • 2022-08-17
  • 2019-11-13
  • 1970-01-01
相关资源
最近更新 更多