Scala 如何在创建域模型时为字符串和其他数据类型创建更具体的类型

Scala 如何在创建域模型时为字符串和其他数据类型创建更具体的类型,scala,domain-driven-design,Scala,Domain Driven Design,在域建模时,我如何确保两种类型——User和Place不交换它们的name字段,这两种字段的类型为String trait用户{ val firstName:String val lastName:String } 对象用户{ 最终类Live(val firstName:String,val lastName:String)扩展了用户 def apply(firstName:String,lastName:String):User=new-Live(firstName,lastName) } 特

在域建模时,我如何确保两种类型——
User
Place
不交换它们的
name
字段,这两种字段的类型为
String

trait用户{
val firstName:String
val lastName:String
}
对象用户{
最终类Live(val firstName:String,val lastName:String)扩展了用户
def apply(firstName:String,lastName:String):User=new-Live(firstName,lastName)
}
特征位置{
val名称:String
}
对象位置{
最终类Live(val名称:String)扩展位置
def apply(名称:字符串):Place=new Live(名称)
}
val a=用户(“Tushar”、“Mathur”)
val b=地点(“孟买”)
val c=地点(a.名字)
//如何禁用此功能^

这在Scala中受支持,如下例所示。有一些库可以简化样板文件,但我只展示了最简单的选项:

// define more restrictive String-like types. AnyVal construction can be free from 
// overhead with some caveats.
case class UserName(name: String) extends AnyVal
case class PlaceName(name: String) extends AnyVal

// define your classes (I've changed them a bit for brevity):
case class User(name: UserName)
case class Place(name: PlaceName)

// implicits for convenience of construction:
implicit val strToUserName = UserName(_)
implicit val strToPlaceName = PlaceName(_)

// test it out:
scala> val u = User("user")
u: User = User(UserName(user))

scala> val p = Place("place")
p: Place = Place(PlaceName(place))

// as expected you CAN'T do this:
scala> User(p.name)
<console>:17: error: type mismatch;
 found   : PlaceName
 required: UserName
       User(p.name)
              ^

// comparison test:
scala> p.name == u.name
<console>:16: warning: comparing case class values of types PlaceName and UserName using `==' will always yield false
       p.name == u.name
              ^
res3: Boolean = false

// you can still get at the string value:
scala> p.name
res6: PlaceName = PlaceName(place)

scala> p.name.name
res5: String = place
//定义更严格的字符串类型。AnyVal构造可以不受
//头顶上有一些警告。
案例类用户名(名称:String)扩展了AnyVal
案例类PlaceName(名称:String)扩展了AnyVal
//定义类(为了简洁起见,我对它们做了一些修改):
案例类用户(名称:用户名)
案例类地点(名称:PlaceName)
//为便于施工,建议:
隐式val strToUserName=用户名
隐式val strToPlaceName=PlaceName(41;
//测试一下:
scala>val u=用户(“用户”)
u:User=User(用户名(用户))
scala>val p=Place(“Place”)
p:Place=Place(地名(Place))
//正如所料,您不能这样做:
scala>用户(p.name)
:17:错误:类型不匹配;
找到:地名
必需:用户名
用户(p.name)
^
//比较试验:
scala>p.name==u.name
:16:警告:使用“==”比较PlaceName和UserName类型的大小写类值将始终产生false
p、 name==u.name
^
res3:Boolean=false
//您仍然可以获取字符串值:
scala>p.name
res6:PlaceName=PlaceName(地点)
scala>p.name.name
res5:String=place