出现差异的原因记录在 ScalaDoc 中。
包裹字符串:
此类 和 之间的区别在于StringOps
调用转换器方法(例如filter
和)map
将产生一个类型的对象WrappedString
而不是String
.
字符串操作:
此类 和 之间的区别在于WrappedString
调用转换器方法(例如filter
和)map
将产生一个String
对象,而 aWrappedString
将保持为 a WrappedString
。
两者都派生自collection.GenSeqLike
which 定义了一个 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]
.