【发布时间】:2021-06-27 01:12:25
【问题描述】:
我认为在 Scala 中Map[Class[_ <: SomeSuperClass], V] 创建了一个不可变映射,使得K 是classOf[T],其中T 是SomeSuperClass 的直接或间接子类。我可能错了,这可能与我的问题相关,也可能不相关。
我发现我无法真正访问 V 值。如何将SomeSuperClass 的子类映射到V 值?
例如,扑克牌。在二十一点中,J、Q 和 K 的值都与 10 相同。但在其他游戏中,它们可能具有不同的值,例如 J 的值是 11,Q 的值是 12,K 的值是 13。
给定cards包中的抽象Rank类和子类Ace、Two、Three、...、King,blackjack包中的类可以有一个函数如下:
def valueOf(rank: Rank): Int = rank match {
case _: Ace => 11 // TODO: Figure out when value 1
case _: King => 10
case _: Queen => 10
case _: Jack => 10
case _: Ten => 10
case _: Nine => 9
case _: Eight => 8
// etc.
}
在 Java 中,我会(并且确实)只使用枚举类型。 Scala 中有一种叫做密封类的东西,但实际上这似乎比 Java 中的枚举要麻烦得多。或者可能我还没弄清楚如何正确使用它们。
但我更喜欢一种更灵活的方法,允许我或其他任何人添加卡片等级,并以最少的麻烦为这些等级进行估值(例如,通过简单的子类化 Rank)。像这样的:
class Valuations(val map: Map[Class[_ <: Rank], Int]) {
def valueOf(rank: Rank): Int = {
val key = rank.getClass
if (map.contains(key) map.get(key) else {
throw new NoSuchElementException("No match for " + rank.toString)
}
}
}
我可以让 IntelliJ 给我一个绿色复选标记,但我无法让我的单元测试通过。
在 Java 版本中,枚举类型 Rank 具有值函数,因此您可以依赖 Rank 实例来获得该值。但是,即使我不想添加新的卡片等级,为 int 以外的类型的值添加新的映射也可能很笨拙,并且不符合单一职责原则的精神。
在 Scala 中肯定有更优雅的解决方案。如何将这些类型匹配为值的键,同时保持添加不同子类型的灵活性而不重写任何已经存在的内容?
【问题讨论】:
-
Scala 3 确实有枚举,如果你愿意尝试的话。
-
@OriginalOriginalOriginalVI 我是。但是我们的行业仍然使用 Java 8?也许不是。