首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何定义在运行时工作的联合类型?

如何定义在运行时工作的联合类型?
EN

Stack Overflow用户
提问于 2016-07-11 04:02:50
回答 2查看 1.5K关注 0票数 3

下面是关于如何定义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类返回给它们。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38295995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档