鉴于这些定义:
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实现中的错误/缺点吗?
答案 0 :(得分:1)
是的,String
是一个Java类,没有一点帮助就没有mkString
方法。
在JVM中运行并使用它的本机String
类来限制Java代码的速度和兼容性是一个限制。
mkString
根据需要添加到String
,使用隐式转换为StringOps
。当您将name
转换为HasMkString
时,String-&gt; 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.
或更好地避免结构类型,因为它可能使用反射并导致代码更慢。
答案 1 :(得分: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