正如我所见,String
和Long
这样的原始类型无法扩展,因为它们被定义为final
。但这对于类型安全的方法来说是一种遗憾。在不围绕的代码中字符串操作,我更喜欢键入我的数据,而不是使用String,Long,Int等:只要我使用类型安全的语言,我就像我的代码真的从头开始打字。
根据实验和as demonstrated on a very old question类型别名似乎不利于此。目前,我将使用以下内容:
case class DomainType(value: String)
代价是必须使用需要值的.value
。
scala 2.8之后是否还引入了其他语言功能,可以巧妙地促进类型安全的子类型原语?是否存在代理基础值的任何对象覆盖,但仍然会发生类型匹配?
答案 0 :(得分:6)
我不同意你的思维方式。 Java原语无法扩展,因为它们是原语(btw String
不是原语)。它们是字节代码类型的直接表示。从编译器的角度来看,扩展它们是没有意义的。
Scala使用 pimp my library 模式处理此问题,例如使用类RichInt。这允许在没有对象实例化(通过value classes和implicits)的情况下(主要)向现有类型添加新方法。另请查看implicit classes。
implicit class DomainType(val o: String) extends AnyVal {
def myDomainMethod: Int = o.size
}
"hello".myDomainMethod // return 5
问题,这并不允许您像对待DomainType
那样限制类型。但类型类可以帮助你。
这里我们要为类型添加约束,而不继承。如this link中所述,
因此,类型类允许ad-hoc和retroactive多态。依赖于类型类的代码可以扩展而不需要创建适配器对象。
以下示例显示方法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
当然这会降低代码的清晰度,我不会推荐它。
答案 1 :(得分:2)
对于基本类型,您可以使用值类。它们不扩展基本类型,但它们在内部由JVM基元表示,因此它们在大多数情况下避免了运行时开销。您可以找到更多信息here。
答案 2 :(得分:0)
似乎标签类型形式scalaz将是一个很好的选择。
val a: Int @@ DomainType = Tag(5)
有关用法的更多信息,请查看以下优秀系列文章: http://eed3si9n.com/learning-scalaz/Tagged+type.html不幸的是,似乎必须从scalaz 7.1开始明确调用unwrap,但是使用scalaz7可以调用类似的东西:
a * 5
但根据您的需要,这可能仍然有用