Scala 2.11 中的类型化原语
Posted
技术标签:
【中文标题】Scala 2.11 中的类型化原语【英文标题】:Typed primitives in Scala 2.11 【发布时间】:2015-03-28 10:36:27 【问题描述】:正如我所见,String
和 Long
等原始类型无法扩展,因为它们被定义为 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 中的类型化原语的主要内容,如果未能解决你的问题,请参考以下文章