字符串隐式转换列表,如+ =

时间:2011-08-29 19:07:34

标签: scala implicit-conversion

请考虑以下代码段。 + =不是java.lang.String的成员,所以我猜有某种隐式转换正在进行中。如何查找作用于String的此类预定义隐式转换的列表?

scala> var x = "asdf"
x: java.lang.String = asdf

scala> x += x

scala> x
res2: java.lang.String = asdfasdf

4 个答案:

答案 0 :(得分:13)

你选择了一个特别糟糕的例子。从某种意义上说,+=String的一部分。请参阅java.lang.String的Javadoc上的此评论:

  

Java语言为字符串提供特殊支持   连接运算符(+),以及其他对象的转换   字符串。

您必须查找Java language specification才能找到有关它的更多信息(15.18.1)。但是,再一次,Scala不是Java,因此+也是Scala language specification(12.3.1)的一部分。

到目前为止,我已经谈过+,而不是+=。但是,Scala有一个特殊的语法糖用于分配。如第6.12.4节所述,除<=>=!=和以=开头的运算符外,任何运算符符号(请参阅第1章中的“运算符”)如果它不作为方法存在,那么以等号结束的将被重新解释。具体地,

x += 1

将被重新解释为

x = x + 1

无论x是否为var,都会发生这种情况,因此有时可能会看到错误消息“reassignment to val”。

因此,正如您所看到的,+=实际上是String的一部分,通过Scala规范中复制的Java规范中的异常,加上一些语法糖。

这并不意味着java.lang.String中没有可以通过隐式转换与其一起使用的方法。不过,我会把它留给其他答案。如果我是你,我会改变问题中的方法,使其正确。此外,在Stack Overflow中无法搜索+=

答案 1 :(得分:8)

你需要查看scala.Predef - 所有定义的含义总是在范围内(所以你不需要导入它们)。

如果你查看it's source code,你会发现这一部分:

// Strings and CharSequences ------------

...

implicit def augmentString(x: String): StringOps = new StringOps(x)
implicit def unaugmentString(x: StringOps): String = x.repr

...

答案 2 :(得分:4)

StringOps定义String的隐式转化。它会被导入scala.Predef中的范围以及其他有用的东西。

答案 3 :(得分:4)

不是String特有的,但Scala REPL有一个简洁的功能,可以看到所有范围内的含义:

scala> :implicits
No implicits have been imported other than those in Predef.

scala> :implicits -v
/* 96 implicit members imported from scala.Predef */
  /* 66 inherited from scala.Predef */
  implicit def Double2double(x: jl.Double): Double
  implicit def byte2double(x: Byte): Double
  implicit def char2double(x: Char): Double
  ...

  /* 30 inherited from scala.LowPriorityImplicits */
  implicit def genericWrapArray[T](xs: Array[T]): mutable.WrappedArray[T]
  implicit def wrapBooleanArray(xs: Array[Boolean]): mutable.WrappedArray[Boolean]
  implicit def wrapByteArray(xs: Array[Byte]): mutable.WrappedArray[Byte]
  ...

值得注意的是,implicits不必在范围内应用。例如,我们可以在伴随对象中定义隐式转换,

case class Foo(s: String)
object Foo { implicit def string2Foo(s: String) = Foo(s.reverse) }

然后应用它,即使它不在范围内,

scala> val f: Foo = "hello"
f: Foo = Foo(olleh)

搜索Foo随播广告属性,因为目标类型为Foo。有关详细信息,请参阅Daniel Sobral对:Where does Scala look for implicits?

的回答