Scala:String" +" vs" ++"

时间:2015-10-12 05:42:39

标签: java string scala operators

我是Scala的新手,我已经看到了在Scala中连接字符串的代码,如下所示:

"test " ++ "1"

我已经测试了,它也写在Scala Doc

"test " + "1"

所以我的理解是+就像Java字符串+++更强大,可以接受更多类型的参数。此外++似乎对List等其他内容具有普遍性。我想知道我的理解是否正确。和其他任何差异?什么时候应该只用于字符串连接?

5 个答案:

答案 0 :(得分:11)

有助于查看scala.Predef以了解究竟发生了什么。

如果您在那里查看,则表明Scala中的String只是java.lang.String的别名。换句话说,+上的String方法会被转换为Java +运算符。

因此,如果Scala String只是一个Java String,那么++方法如何存在,您可能会问。 (好吧,我至少要问。)答案是,String方法提供了从WrappedStringwrapString的隐式转换,也在Predef

请注意++接受任何GenTraversableOnce实例,并将该实例中的所有元素添加到原始WrappedString。 (请注意,文档错误地指出该方法返回WrappedString[B]。这必须是错误的,因为WrappedString没有采用类型参数。)您将获得的内容是String(如果你添加的内容是Seq[Char])或某些IndexedSeq[Any](如果它不是)。

以下是一些例子:

如果您向String添加List[Char],则会获得一个字符串。

scala> "a" ++ List('b', 'c', 'd')
res0: String = abcd

如果您向String添加List[String],则会获得IndexedSeq[Any]。事实上,前两个元素是Char s,但最后三个元素是String s,如后续调用所示。

scala> "ab" ++ List("c", "d", "e")
res0: scala.collection.immutable.IndexedSeq[Any] = Vector(a, b, c, d, e)

scala> res0 map ((x: Any) => x.getClass.getSimpleName)
res1: scala.collection.immutable.IndexedSeq[String] = Vector(Character, Character, String, String, String)

最后,如果您使用StringString添加++,则会返回String。这样做的原因是WrappedString继承自IndexedSeq[Char],因此这是一种将Seq[Char]添加到Seq[Char]的复杂方式,它会返回Seq[Char] }。

scala> "abc" + "def"
res0: String = abcdef

正如Alexey所说,这些都不是一个非常微妙的工具,所以你最好不要使用string interpolationStringBuilder,除非有充分的理由不这样做。

答案 1 :(得分:3)

StringTraversableLike,这意味着它可以被分解为一系列元素(字符)。这就是++来自的地方,否则你无法在String上做++++仅在其右侧(或该函数的参数)是可解组合类型(或可遍历)时才起作用。

现在String如何成为TraversableLike?这就是Predef中定义的含义发挥作用的地方。其中一个隐式将正常String转换为WrappedString,其中WrappedString.canBuildFrom具有基本上以这种方式工作的所有粘合剂:

WrappedString.canBuildFrom - > StringBuilder - > StringLike - > IndexedSeqOptimized - > IndexedSeqLike - > SeqLike - > IterableLike - > TraversableLike

由于Predef中定义的含义已经在范围内,因此可以编写如下代码:

"test " ++ "1"

现在你的问题:

  

我想知道我的理解是否正确。和其他任何差异?

是的,你的理解是正确的方向。

  

什么时候应该用于字符串连接?

对于字符串连接,显然"test " + "1"创建的对象越少,函数调用次数越少。但是,我总是喜欢字符串插值,如下所示:

val t1 = "test"
val t2 = "1"
val t3 = s"$t1 $t2"

更具可读性。

更多详情:

答案 2 :(得分:2)

  

所以我的理解是+就像Java String +但是++更强大,可以接受更多类型的参数

问题是,在这个意义上,字符串上的+更强大:它可以接受任何参数,就像在Java中一样。这通常被认为是错误的(特别是因为它也适用于右边的字符串),但我们几乎坚持使用它。正如你所说,++是一种通用的收集方法,更加类型安全("test " ++ 1不会编译)。

  

什么时候应该用于字符串连接?

我更喜欢+。但是,对于许多人(我甚至说最多),使用你想要的东西都不是:改用string interpolation

val n = 1
s"test $n"

当然,在从许多部分构建字符串时,请使用StringBuilder

答案 3 :(得分:0)

++不一定“更强大”,但它通常用作连接/追加操作。但是,它不执行分配。 IE listX ++ y将附加到listX,但i++不会增加整数i(因为它分配给变量而不是变异)。

这至少是我的理解。我不是斯卡拉专家。

答案 4 :(得分:0)

String中有StringOpsscala.Predef的隐式转换。 ++方法定义了StringOps方法。因此,无论何时执行str1 ++ str2,scala编译器基本上(从编码器的角度来看)将str1包裹在StringOps中并调用++ StringOps方法}。请注意,StringOps本质上是一种IndexedSeq,因此++运算符非常灵活,例如。

"Hello, " ++ "world!"  //results in "Hello, world" with type String
"three" ++ (1 to 3)    //results in Vector('t', 'h', 'r', 'e', 'e', 1, 2, 3) with type IndexedSeq[AnyVal]