下面是关于如何定义union types in Scala的一组出色的答案。我一直在使用Miles Sabin对Union类型的定义,但有一个问题仍然存在。
如果直到运行时才知道类型,那么如何处理这些类型呢?例如:
trait inv[-A] {}
type Or[A,B] = {
type check[X] = (inv[A] with inv[B]) <:< inv[X]
}
case class Foo[A : (Int Or String)#check](a: A)
Foo(1) // Foo[Int] = Foo(1)
Foo("hi") // Foo[String] = Foo(hi)
Foo(2.0) // Error!
这个例子之所以有效,是因为参数A
在编译时是已知的,调用Foo(1)
实际上就是在调用Foo[Int](1)
。但是,如果参数A
直到运行时才知道,该怎么办?也许你正在解析一个包含Foo
数据的文件,在这种情况下,Foo
的类型参数直到你读取数据后才知道,在这种情况下没有简单的方法来设置参数A
。
我能想到的最好的解决方案是:
将
Foo
。在我的例子中,这是不可行的,因为我的case类实际上包含几十个联合类型,因此将有数百种类型组合进行模式匹配。(String or Int)
,因此您只需传递一个类型,当您使用它创建Foo
时,该类型将传递type类约束。然后返回Foo[_]
。这让Foo用户重新承担了确定每个字段的类型的责任(因为它们看起来是类型Any),但至少它推迟了知道类型的时间,直到字段被实际使用,在这种情况下,模式匹配似乎更容易处理。第二个解决方案如下所示:
def parseLine: Any // Parses data point, but can be either a String or
// Int, so returns Any.
def mkFoo: Foo[_] = {
val a = parseLine.asInstanceOf[Int with String]
Foo(a) // Passes type constraint now
}
在实践中,我最终使用了第二种解决方案,但我想知道是否有更好的方法可以做?
陈述问题的另一种方法是:返回Union类型意味着什么?函数只能返回单个类型,我们对Miles Sabin联合类型使用的技巧只适用于您传入的类型,而不适用于您返回的类型。
PS。对于上下文,为什么这在我的案例中是一个问题,是因为我正在从一个Json模式文件生成一组case-classes。Json自然支持联合类型,所以我想让我的case类也反映这一点。这在一个方向上效果很好:用户创建要序列化到Json的case-case。但在另一个方向上变得棘手:用户解析Json文件,以将一组填充的case类返回给它们。
发布于 2016-07-11 04:22:53
Scala对这个问题的“标准”解决方案是使用一个普通的联合判别类型(即完全放弃真正的联合类型):
sealed trait Foo
case class IntFoo(x: Int) extends Foo
case class StringFoo(x: String) extends Foo
正如您所观察到的,这反映了这样一个事实:成员的特定类型是一个运行时值;Foo
实例的JVM type-tag提供了这个运行时值。
Miles Sabin的联合类型的实现非常聪明,但是我不确定它是否提供了任何实际的好处,因为它只限制了可以进入Foo
的东西的类型,但是为Foo
的用户提供了这种限制的可计算版本,就像match
为您提供了sealed
特征的可计算版本一样。一般来说,要使限制有用,它需要两个方面:检查只放入正确的内容,以及允许相同的正确内容从另一端出来的提取器(也称为消除器)。
也许,如果你给出一些解释,为什么你要寻找一个更纯粹的联盟类型,它将阐明常规的歧视联盟是否足够,或者如果你真的需要更多的东西。
发布于 2016-07-11 05:09:04
每个用于Scala的JSON解析器都需要定义良好的类型,以便将JSON转换为这些类型,即使某些字段必须删除,这是有原因的:您不能处理不知道其类型的内容。
举个例子,假设你有a
,也许a
是一个String
,也许它是一个Int
,但是你不知道它是什么。为什么你可以用a
进行计算,而不知道它的类型?例如,如果你事先不知道它是一个数字,为什么你的代码要计算所有a
的和呢?
通常,答案是在运行时对具有未知特征的数据执行用户提供的数据操作,因为用户自己看到它是一个数字,并决定他们想知道该字段的总和是多少。好吧,但如果是这样的话,你就错了。
在Scala中有一种定义良好的方式来表示JSON数据(就此而言,还有任何与JSON具有相同特征的数据。它使用类的层次结构。json值可以是json对象、数组或多个原语中的一个。json对象包含一系列键/值对,这些键/值对的键是json字符串,值是json值。诸若此类。这很容易表示,而且已经有很多库在这样做了。事实上,有很多这样的库,以至于有一个名为Json4s的项目,它提供了一个统一的应用程序接口,可以由前面提到的许多库使用和实现。
类似Miles Sabin的Shapeless库提供的记录,是为了在输入没有良好定义的模式时使用,但是程序知道它需要从该输入中得到什么。是的,如果a
是Int
或String
,程序可能知道如何处理它,但不是所有可能的值。
https://stackoverflow.com/questions/38295995
复制相似问题