在scala中是否可以拥有联合类型的集合 . 有几种方法可以讨论联合类型here评价最高的答案感觉最本土,我有这样的事情:
sealed trait StringOrNumber[T]
object StringOrNumber {
implicit object IntWitness extends StringOrNumber[Int]
implicit object StringWitness extends StringOrNumber[String]
}
但是当我试图制作一个包含两者的 Map 时
val m: Map[String, Any] = Map("str" -> "hellp", "int" -> 32)
scala编译器将其视为[String,Any]的映射 . 有没有办法告诉scala编译器这是一个map [String,StringOrNumber]
编辑:
我不认为使用上面的方法可以创建一个字符串或联合的集合 . 我认为它需要是一种联合类型的另一种方法,因为上面类似于重载方法而不是类型系统中的真正联合类型
6 回答
在当前版本的Scala中,最接近的运行时联合类型仿真是在扩展一些密封特征的case类中包装union的类型 . 它是样板文件,并且在
AnyRef
类型上添加了一个额外的包装层,但它可以工作,它比仅使用Any
更好,您还可以从联合类型添加隐式转换:现在您可以定义
Map
:Scala已经内置了
case
-classes,它们能够表示其他类型的任意标记的不相交联合 .在您的情况下,定义
StringOrNumber
的最简单方法是:如果您不想为此创建额外的特征,并且如果您只有两种类型,请使用
Either
:您复制的部分答案不完整 . 还有另一部分匹配 . 并且它表明这种类型的联合在运行时工作 . 所以一般来说,你混合了两个不同的东西:编译时类型联合(这也是你提到的问题,最初是由Miles Sabin编写的here),它影响编译器检查和运行时类型检查 .
所以,只要你使用运行时方法,scala编译器就是不理解这个联合,并建议使用Any
你应该写
这个功能现在正在Dotty中开发 . 据我所知,它会是这样的
和
但是dotty将在明年推出 . 现在,您可以使用您的方法,但这有点棘手,需要隐含 . 您也可以尝试使用任何一种类型(仅当您有2种泛型类型时),并且您还可以注意scalaz库 . 这都是关于类型级编程的 .
你试过了吗:
在这种情况下,您可能还需要显式构造
StringOrNumber
实例以使其工作 .让我向您介绍我的解决方案,使用逆变和类型约束:
此解决方案的问题是此处不接受Int或String的扩展 . 在此处输入的值被检查约束为"Contravariant"至
Int with String
.有一种解决方法,你必须绕过类型推断,并在type参数中提供基类,如下所示: