4

我只是在学习 Scala,所以如果已经讨论过这个问题,我深表歉意,但以下内容对我来说似乎有点奇怪:

scala> import scala.collection.immutable._
import scala.collection.immutable._

scala> val st1 = new WrappedString("Hello")
st1: scala.collection.immutable.WrappedString = Hello

scala> val st2 = new StringOps("Hello")
st2: scala.collection.immutable.StringOps = Hello

scala> st2 == st1
res0: Boolean = true

scala> st1 == st2
res1: Boolean = false

谁能解释一下?我正在使用 Scala 版本 2.10.0-M4。我没有用其他任何版本尝试过这个。

4

1 回答 1

7

出现差异的原因记录在 ScalaDoc 中。

包裹字符串:

此类 和 之间的区别在于StringOps调用转换器方法(例如filter和)map将产生一个类型的对象WrappedString而不是String.

字符串操作:

此类 和 之间的区别在于WrappedString调用转换器方法(例如filter和)map将产生一个String 对象,而 aWrappedString将保持为 a WrappedString

两者都派生自collection.GenSeqLikewhich 定义了一个 equals 方法:

override def equals(that: Any): Boolean = that match {
  case that: GenSeq[_] => (that canEqual this) && (this sameElements that)
  case _ => false
}

两者都实现了canEqual(派生自collection.IterableLike),它总是返回 true。但StringOps不是collection.GenIterable

scala> st1 sameElements st2
<console>:13: error: type mismatch;
 found   : scala.collection.immutable.StringOps
 required: scala.collection.GenIterable[?]
              st1 sameElements st2
                               ^

鉴于WrappedString

scala> st2 sameElements st1
res13: Boolean = true

所以很明显为什么第一种情况会返回true,而另一种情况会返回false

但为什么两者都存在?我不完全确定为什么要这样设计,但我认为这是因为 String 不是 Scala 中的集合。当我们对一个字符串进行一些操作时,"abc" flatMap (_+"z")我们想要取回另一个字符串,即使它并不总是可能的,如"abc" map (_+1). 这就是这样StringOps做的。但是当我们有一些方法时,我们应该def x[A](s: Seq[A]) = s.getClass如何用一个字符串来调用它呢?在这种情况下,我们需要WrappedString

scala> x("a")
res9: Class[_ <: Seq[Char]] = class scala.collection.immutable.WrappedString

所以,StringOps更轻量级WrappedString。它允许我们在简单的旧方法上调用一些方法,java.lang.String而不会产生太多开销。在 2.10中StringOps扩展AnyVal。这意味着它是一个值类,它的存在可以通过 scalac 进行优化(通过包装字符串不再有运行时开销)。相比之下WrappedString,我们可以将 String 作为真正的集合处理 - 作为IndexedSeq[Char].

于 2012-06-17T10:11:46.610 回答