标记类型:类型不匹配

时间:2014-01-15 10:10:21

标签: scala scalaz

我尝试使用scalaz中的Tagged Type来加强类型安全性。

我遇到了一个我不明白的警告和错误。

你能解释我两个吗?

以下是控制台的输出:

scala> sealed trait PostId
defined trait PostId

scala> def PostId(l: Long) : Long @@ PostId = Tag[Long, PostId](l)
PostId: (l: Long)scalaz.@@[Long,PostId]
warning: previously defined trait PostId is not a companion to method PostId.
Companions must be defined together; you may wish to use :paste mode for this.

scala> case class Post(id: PostId)
defined class Post

scala> Post(PostId(2l))
<console>:26: error: type mismatch;
 found   : scalaz.@@[Long,PostId]
    (which expands to)  Long with AnyRef{type Tag = PostId}
 required: PostId
              Post(PostId(2l))

1 个答案:

答案 0 :(得分:3)

在您的示例中,PostId只是一种标记类型。 实际的tagg- ed 类型(您应该操作的类型)是Long @@ PostId

错误是你已经定义Post来获取PostId的实例,当你真的想让它采用Long @@ PostId的实例时,因此类型不匹配。

我建议将PostId重命名为PostIdTag,并将PostId定义为Long @@ PostId的别名:

sealed trait PostIdTag
type PostId = Long @@ PostIdTag

def PostId(l: Long) : PostId = Tag[Long, PostIdTag](l)

然后,您可以按原样保留Post定义。

更新:事实证明,scalaz标记类型似乎只适用于类型&lt ;: AnyRef,即无法从AnyVal子类创建标记类型型。

然后,解决方案是将Long替换为java.lang.Long(这是透明的,因为scala会自动将java.lang.Long值转换为Long):

sealed trait PostIdTag
type PostId = java.lang.Long @@ PostIdTag
def PostId(l: java.lang.Long) : PostId = Tag[java.lang.Long, PostIdTag](l)
case class Post(id: PostId)
Post(PostId(2l))