2016-05-11 101 views
5

我是用無形的標籤,寫類似的代碼這一點 -斯卡拉類型和編譯

import shapeless.tag 
import [email protected]@ 

object Typeplay { 
    trait StringTrait 
    type MyString = String @@ StringTrait 

    case class StringClass(mps: MyString) 
    val stringClass = StringClass(tag[StringTrait]("test")) 
} 

而這個代碼將無法編譯。斯卡拉編譯器抱怨最後一行代碼說 -

[error] found : String("test") 
[error] required: shapeless.tag.Tagged[in.bharathwrites.Typeplay.StringTrait] with String 
[error] val stringClass = StringClass(tag[StringTrait]("test")) 

我不明白我在做什麼錯了。所以我做了一個小的變化,以我的代碼 -

import shapeless.tag 
import [email protected]@ 

object Typeplay { 
    trait StringTrait 
    type MyString = String @@ StringTrait 

    case class StringClass(mps: MyString) 

    val stringTag = tag[StringTrait]("test") 
    val stringClass = StringClass(stringTag) 
} 

這基本上只是使用顯式變量的標記。此代碼編譯!

這怎麼可能?爲什麼第一個程序不能編譯,第二個程序呢?

回答

1

在這種情況下,似乎類型別名混淆了類型推斷。如果你提供明確的類型的tag方法,一切工作正常:

StringClass(tag[StringTrait][String]("test")) 

StringClass(tag[StringTrait]("test"):String @@ StringTrait) 

,或者如果你聲明PARAM StringClass直接:

case class StringClass(mps: String @@ StringTrait) 

StringClass(tag[StringTrait]("test")) 

顯然Scala編譯器的限制。


UPD。坦率地說,我不知道你在這裏命名的類型推斷有什麼確切的限制。我對相關的開放式錯誤的搜索沒有結果。

關於第一個例子。如果你看一下tag實施一切都變得清晰:

object tag { 
    def apply[U] = new Tagger[U] 

    trait Tagged[U] 
    type @@[+T, U] = T with Tagged[U] 

    class Tagger[U] { 
    def apply[T](t : T) : T @@ U = t.asInstanceOf[T @@ U] 
    } 
} 

所以,當你這樣做:

tag[StringTrait][String]("test") 

你基本上做到這一點:

tag.apply[StringTrait].apply[String]("test") 
+0

能否請您提供一些線索瞭解這個限制是什麼。另外,我們對於如何將一個值轉換爲多於一種類型感到困惑,正如您在第一個建議中所做的那樣。它的工作原理,但我不明白如何。我嘗試了一個小程序,看看它是否適用於所有場景,並且它不是 - – Bharadwaj

+0

scala> def myToString [A](s:A)= s.toString myToString:[A](s:A)字符串 scala > myToString [String] [Object](「hello」) :13:error:method myToString:(s:String)String不接受類型參數。 myToString [String] [Object](「hello」) ^ scala> myToString [String](「hello」) res1:String = hello' – Bharadwaj

+0

@Bharadwaj,請參閱更新。 – Aivean