2014-01-15 149 views
1

我嘗試使用scalaz中的標記類型來加強類型安全性。標籤類型:類型不匹配

我遇到了一個警告和一個我不明白的錯誤。

你能解釋我兩個嗎?

這裏是控制檯輸出:

scala> sealed trait PostId 
defined trait PostId 

scala> def PostId(l: Long) : Long @@ PostId = Tag[Long, PostId](l) 
PostId: (l: Long)[email protected]@[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 : [email protected]@[Long,PostId] 
    (which expands to) Long with AnyRef{type Tag = PostId} 
required: PostId 
       Post(PostId(2l)) 

回答

3

在你的榜樣,PostId只是一個標籤類型。 實際的tagg-ed類型(您應該操縱的類型)是Long @@ PostId

錯誤在於,如果您確實需要使用Long @@ PostId的實例(因此類型不匹配),則您已定義Post以獲取PostId的實例。

我建議重命名PostIdPostIdTag和定義PostId作爲別名Long @@ PostId

sealed trait PostIdTag 
type PostId = Long @@ PostIdTag 

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

然後你就可以保持你的Post定義爲。

UPDATE:事實證明,scalaz標籤類型似乎只與類型<工作:AnyRef,即一個不能創建從AnyVal子類型標記類型。

然後將溶液是更換Longjava.lang.Long(其透明地工作,因爲Scala將自動轉換java.lang.LongLong):

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)) 
+0

:21:錯誤:非法循環引用涉及類型帖子ID 類型帖子ID = Long @@ PostId –

+0

我的不好,應該是'Long @@ PostIdTag',而不是'Long @@ PostId'。我更新了我的答案。 –

+0

一個新的錯誤:scala> case class Post(id:PostId) error:type mismatch; 找到的:任何 必需:AnyRef 注意:任何不會隱式轉換爲AnyRef。您可以安全地使用 模式匹配'x:AnyRef'或強制執行'x.asInstanceOf [AnyRef]'來執行此操作。 –