2013-08-31 32 views
0

根據這些定義:結構類型轉換不適用於字符串?

type HasMkString = { def mkString(sep:String):String } 
val name = "John" 
val names = List("Peter", "Gabriel") 

而鑑於這些事實:

name.mkString("-") // => "J-o-h-n" 

name.isInstanceOf[HasMkString] // => true 
names.isInstanceOf[HasMkString] // => true 

雖然這個工程:

names.asInstanceOf[HasMkString].mkString("-") 
// => Peter-Gabriel 

這不起作用:

name.asInstanceOf[HasMkString].mkString("-") 

java.lang.NoSuchMethodException: java.lang.String.mkString(java.lang.String) 
at java.lang.Class.getMethod(Class.java:1624) 
at .reflMethod$Method1(<console>:10) 
at .<init>(<console>:10) 
at .<clinit>(<console>:10) 
at .<init>(<console>:7) 
at .<clinit>(<console>) 
at $print(<console>) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:601) 

這是爲什麼? 是因爲String是一個Java類嗎? 我可以解決這個問題嗎? 這是Scala實現中的缺陷/缺點嗎?

回答

1

是的,String是Java類,沒有一點幫助就沒有mkString方法。

這是在JVM中運行的一種限制,並且使用它的本機String類來提高速度和與Java代碼的兼容性。

mkString按需添加到String,使用隱式轉換爲StringOps。當您將name轉換爲HasMkString時,String-> StringOps隱式轉換不再適用,因此您將失去所有額外的方法。

的解決辦法是要麼更換

def f (name: HasMkString) = name.mkString ("-") 

def f (name: HasMkString) = 
    if (name.isInstanceOf[String]) name.asInstanceOf[String].mkString ("-") 
    else name.mkString ("-") 

或不明確的強制轉換爲結構型扔掉類型的信息,如

def f (name: HasMkString) = name.mkString ("-") 
f ("John") // Ok. Scala is smart enough to wrap the String here. 
f ("John".asInstanceOf[HasMkString]) // Error. String type is hidden. 

或者更好,但避免結構類型,因爲它可能使用反射並導致緩慢呃代碼。

+0

謝謝!這解釋了它。通常我不會做這樣的事情。我只是試圖翻譯一段Ruby代碼,然後再細化爲更習慣的Scala。 –

1

添加到@artemgr回答,請注意它是不是觸發隱式轉換的asInstanceOf

scala> type HasMkString = { def mkString(sep:String):String } 
defined type alias HasMkString 

scala> def f (name: HasMkString) = name.mkString ("-") 
f: (name: HasMkString)String 

scala> f("AAA") 
res0: String = A-A-A