【发布时间】:2018-04-02 22:36:47
【问题描述】:
为了引入更多的类型安全性,我们可以使用shapeless 提供的标记类型,或者创建一个扩展AnyVal 的类。使用其中一个有什么区别和优势/劣势?
例子:
trait CountryCodeTag
type CountryCode = String @@ CountryCodeTag
class CountryCode(code: String) extends AnyVal
【问题讨论】:
为了引入更多的类型安全性,我们可以使用shapeless 提供的标记类型,或者创建一个扩展AnyVal 的类。使用其中一个有什么区别和优势/劣势?
例子:
trait CountryCodeTag
type CountryCode = String @@ CountryCodeTag
class CountryCode(code: String) extends AnyVal
【问题讨论】:
type CountryCode = String @@ CountryCodeTag
+; String @@ CountryCodeTag 是String 的子类型,即String 中的所有方法都可以直接使用:countryCode.toUpperCase。
- String @@ CountryCodeTag 可能会意外使用一些 String 预期的地方,即它的类型安全性较低。
- 创建新值有点尴尬:"a".asInstanceOf[String @@ CountryCodeTag] 或 val tagger = new Tagger[CountryCodeTag]; tagger("a")。
- 对 Shapeless 的依赖(虽然这可以手动完成)。
class CountryCode(code: String) extends AnyVal
+;它的类型更安全。
- 来自String 的方法可以通过一些额外的努力获得:
class CountryCode(val code: String) extends AnyVal
new CountryCode(countryCode.code.toUpperCase)
或
class CountryCode(val code: String) extends AnyVal
object CountryCode {
def unapply(...) = ...
}
countryCode match { case CountryCode(code) => new CountryCode(code.toUpperCase) }
或
case class CountryCode(code: String) extends AnyVal
countryCode.copy(code = countryCode.code.toUpperCase)
+;创建新值更自然一点:new CountryCode("a")。
+;没有额外的依赖(它是普通的 Scala)。
【讨论】:
String @@ CountryCodeTag can be accidentally used where some String is expected?
val countryCode: String @@ CountryCodeTag = ??? case class Person(name: String) Person(countryCode)
CountryCodes 都只是 Strings (使用方法 extracted 到伴随对象)所以我想应该没有任何区别。
这两种方法也有不同的性能特点。
标记类型,与值类相反,即使它们的实例被用作例如,也可以防止装箱。列表的元素。
https://failex.blogspot.nl/2017/04/the-high-cost-of-anyval-subclasses.html
【讨论】: