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 实现中的错误/缺点吗?

4

2 回答 2

1

是的,这String是一个 Java 类,没有mkString一点帮助就没有该方法。

这是在 JVM 中运行并使用它的本机String类来提高速度和与 Java 代码的兼容性的限制。

使用隐式转换到按需mkString添加. 当您将其转换为 String->StringOps 时,隐式转换不再适用,因此您失去了所有额外的方法。StringStringOpsnameHasMkString

解决方法是替换

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.

或者更好的是避免结构类型,因为它可能会使用反射并导致代码变慢。

于 2013-09-01T00:40:21.890 回答
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
于 2013-09-01T06:57:29.500 回答