Scala 2.11 中的类型化原语

Posted

技术标签:

【中文标题】Scala 2.11 中的类型化原语【英文标题】:Typed primitives in Scala 2.11 【发布时间】:2015-03-28 10:36:27 【问题描述】:

正如我所见,StringLong 等原始类型无法扩展,因为它们被定义为 final。但这对于类型安全的方法来说是一个遗憾。在围绕例如字符串操作,我更喜欢键入我的数据而不是使用 String、Long、Int 等:只要我使用类型安全的语言,我希望我的代码真正从头开始键入。

根据实验和as demonstrated on a very old question 类型别名似乎并不能促进这一点。目前,我将使用以下内容:

case class DomainType(value: String)

以必须在需要值的地方使用.value 为代价。

在 scala 2.8 或其他版本之后是否引入了任何其他语言功能,可以巧妙地促进类型安全的子类型化原语?是否有任何对象覆盖可以代理底层值,但仍然让类型匹配发生?

【问题讨论】:

完全同意。实际上它比.value 样板文件更糟糕。我的意思是DomainType不能用在String可能的情况下,你应该重新实现json/sql序列化器/反序列化器等。 【参考方案1】:

我不同意你的想法。 Java 原语无法扩展,因为它们是原语(顺便说一句,String 不是原语)。它们是字节码类型的直接表示。从编译器的角度来看,扩展它们是没有意义的。

隐式值类

Scala 使用 pimp my library 模式来处理这个问题,例如使用 RichInt 类。这允许在没有对象实例化的情况下(主要)向现有类型添加新方法(通过value classes 和隐式)。也请查看implicit classes。

implicit class DomainType(val o: String) extends AnyVal 
  def myDomainMethod: Int = o.size


"hello".myDomainMethod // return 5

问题,这不允许您像使用 DomainType 那样限制类型。但是类型类可以帮助你。

类型类

这里我们想给一个类型添加一个约束,而不是继承。正如this link 中所说,

因此,类型类允许临时和追溯多态性。依赖于类型类的代码无需创建适配器对象即可扩展。

以下示例显示方法 foo 如何仅接受类型为隐式 DomainType[T] 的参数。它通过追溯多态性替换了您想要的继承。您还保留了域类型的好处:意图清晰、调用类型安全并且您可以添加新的域方法。

trait DomainType[T] 
  def myDomainMethod(o: T): Int


object DomainType 
  implicit object StringDomainType extends DomainType[String] 
    def myDomainMethod(o: String): Int = o.size
  


def foo[T : DomainType](p: T): Int = 
  implicitly[DomainType[T]].myDomainMethod(p)


foo("hello") // return 5
foo(5) // compilation exception

案例类 + 隐式

如果您的 DomainType 案例类唯一让您烦恼的是调用 .value,您总是可以添加一个为您做这件事的隐式。

implicit def unwrapDomainType(o: DomainType): String = o.value

当然这样会降低代码的清晰度,不推荐。

【讨论】:

谢谢,但也许你可以重写它以更多地关注解决方案,而不是抨击动机。尚不清楚此序列如何完成用例。 好吧,我看这里没有解决方案。很好的叙述,但它几乎围绕着这个问题。 implicit def 没有达到预期的效果 - 一旦您将 两个或更多 域类型映射到 String,它只能隐式捕获 一个他们,或者你的意思是它与第一个代码 sn-p 集成?!?【参考方案2】:

对于原始类型,您可以使用值类。它们不扩展原始类型,但它们在内部由 JVM 原始类型表示,因此它们在大多数情况下避免了运行时开销。您可以找到更多信息here。

【讨论】:

谢谢,虽然不是直接的答案,但这应该会提高性能!【参考方案3】:

看来 scalaz 中的标记类型很合适。

val a: Int @@ DomainType = Tag(5)

有关用法的更多信息,请查看这个优秀的系列文章: http://eed3si9n.com/learning-scalaz/Tagged+type.html 不幸的是,似乎必须从 scalaz 7.1 开始显式调用 unwrap 但是使用 scalaz7 可以调用类似的东西:

a * 5

但根据您的需要,这可能仍然有用

【讨论】:

以上是关于Scala 2.11 中的类型化原语的主要内容,如果未能解决你的问题,请参考以下文章

EF 时间原语类型

Scala 中的高级类型是啥?

Scala中的通用递归类型

Scala中的复和类型

Haskell 在 Scala 中的新类型

Scala中的变量类型和操作