我是Scala的新手,我已经看到了在Scala中连接字符串的代码,如下所示:
"test " ++ "1"
我已经测试了,它也写在Scala Doc
中"test " + "1"
所以我的理解是+
就像Java字符串+
但++
更强大,可以接受更多类型的参数。此外++
似乎对List等其他内容具有普遍性。我想知道我的理解是否正确。和其他任何差异?什么时候应该只用于字符串连接?
答案 0 :(得分:11)
有助于查看scala.Predef
以了解究竟发生了什么。
如果您在那里查看,则表明Scala中的String
只是java.lang.String
的别名。换句话说,+
上的String
方法会被转换为Java +
运算符。
因此,如果Scala String
只是一个Java String
,那么++
方法如何存在,您可能会问。 (好吧,我至少要问。)答案是,String
方法提供了从WrappedString
到wrapString
的隐式转换,也在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)
最后,如果您使用String
向String
添加++
,则会返回String
。这样做的原因是WrappedString
继承自IndexedSeq[Char]
,因此这是一种将Seq[Char]
添加到Seq[Char]
的复杂方式,它会返回Seq[Char]
}。
scala> "abc" + "def"
res0: String = abcdef
正如Alexey所说,这些都不是一个非常微妙的工具,所以你最好不要使用string interpolation或StringBuilder
,除非有充分的理由不这样做。
答案 1 :(得分:3)
String
是TraversableLike
,这意味着它可以被分解为一系列元素(字符)。这就是++
来自的地方,否则你无法在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
中有StringOps
到scala.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]