2015-10-10 26 views
1

我創建了type MyString = String如何強制Scala不使用類型別名的來源?

現在我想讓我的函數只接受我的MyString而不是String,後者根本不應該編譯。

def myFunc(s: MyString) = println(s)同時接受StringMyString ARGS:

scala> type MyString = String 
defined type alias MyString 

scala> def myFunc(s: MyString) = println(s) 
myFunc: (s: MyString)Unit 

scala> val s1: MyString = "aaa" 
s1: MyString = aaa 

scala> myFunc(s1) 
aaa 

scala> val s2: String = "aaa" 
s2: String = aaa 

scala> myFunc(s2) 
aaa 

scala> trait MyString extends String 
<console>:10: error: illegal inheritance from final class String 
     trait MyString extends String 
          ^

scala> s1 
res7: MyString = aaa 

scala> s2 
res8: String = aaa 

scala> s1 == s2 
res9: Boolean = true 

回答

2

type MyString = String 

就表示類型MyStringString,所以他們會在範圍內可用的(主要)互換它們在哪裏定義。

要實施的MyString使用過String,你可以將它定義爲一個包裝類來代替:

case class MyString(value: String) extends AnyVal 

注:擴展AnyVal防止一個額外的類在運行時被實例化 - 見Value Classes獲取更多信息。

你得到你想要這樣的功能參數值的限制,雖然它不來在需要顯式實例化新類型的實例的成本:

scala> val s1: MyString = MyString("aaa") 
s1: MyString = aaa 

scala> myFunc(s1) 
aaa 

scala> val s2: String = "aaa" 
s2: String = aaa 

scala> myFunc(s2) 
<console>:12: error: type mismatch; 
found : String 
required: MyString 
       myFunc(s2) 
        ^
+0

這不完全是我想要的。這樣的包裝是某種柺杖。我希望'MyString'是一個帶有一些額外限制的字符串(比如只有10個字符),而你的建議不允許在'String'之外的函數中使用'MyString'。這就是爲什麼我加上'extend'的原因,如果String不是final的,它會起作用。 – user2317480

+3

@ user2317480是的,這與您的意圖相匹配的程度有限。但是,如果需要在任何需要'String'參數的地方接受'MyString',可以添加一個從'MyString'到'String'的隱式轉換,例如:'implicit def mine2str(myStr:MyString):String = myStr .value'。 – Shadowlands

+0

你的方法的主要缺點是我(作爲開發人員)必須記住字符串應該有10個字符。我想讓編譯器爲我記住它。斷言也不是解決方案,因爲它是運行時。可能需要一些類型級別的魔法a-la。似乎我應該編輯我的問題。 – user2317480

1

另一種解決方案是使用tagged types

type Tagged[U] = { type Tag = U } 
type @@[T, U] = T with Tagged[U] 

trait String10CharsTag 

type String10Chars = String @@ String10CharsTag 

def string10Chars(s: String) = 
    if (s.length == 10) Some(s.asInstanceOf[String10Chars]) else None 

注意String10CharsString一個亞型,因此它可被用作一個參數的方法服用String。它在運行時也總是被表示爲String(AFAIK,但我不明白不是),而值類在某些情況下仍可以實例化。

+0

您可以在類型別名定義中編輯'=='來單個'='嗎?所以編輯應該至少有6個字符,所以我不能自己做。關於答案本身:非常有趣的技術,從未見過它,我需要一些時間來調查它。 – user2317480

+0

@ user2317480已編輯。 –