我只是在学习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。我没试过这个 其他任何版本。
答案 0 :(得分:6)
ScalaDoc中记录了出现差异的原因。
WrappedString:
此类与
StringOps
之间的区别在于调用 变换器方法,如filter
和map
将产生一个对象 键入WrappedString
而不是String
。
StringOps:
此类与
WrappedString
之间的区别在于调用filter
和map
之类的变换器方法将产生String
对象,而WrappedString
将保持为WrappedString
。
两者都派生自定义等于方法的collection.GenSeqLike
:
override def equals(that: Any): Boolean = that match {
case that: GenSeq[_] => (that canEqual this) && (this sameElements that)
case _ => false
}
两者都实现了canEqual
(源自collection.IterableLike
)returns always 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
时,我们如何用String调用它?在这种情况下,我们需要WrappedString
:
scala> x("a")
res9: Class[_ <: Seq[Char]] = class scala.collection.immutable.WrappedString
因此,StringOps
比WrappedString
更轻量级。它允许我们在普通的java.lang.String
上调用一些方法而不需要太多的开销。在2.10 StringOps
扩展AnyVal
。这意味着它是一个值类,它的存在可以通过scalac进行优化(通过包装String不再有运行时开销)。相比之下,WrappedString
允许我们将String作为真实集合处理 - 作为IndexedSeq[Char]
。