我是Scala的新手,我已经看到了在Scala中连接字符串的代码,如下所示:
"test " ++ "1"
我已经测试了,它也写了 Scala Doc
"test " + "1"
所以我的理解是这样的 +
就像Java String +
但 ++
功能更强大,可以采用更多类型的参数。也 ++
似乎是List等其他东西的普遍性。我想知道我的理解是否正确。和其他任何差异?什么时候应该另一个只是为了字符串连接?
我是Scala的新手,我已经看到了在Scala中连接字符串的代码,如下所示:
"test " ++ "1"
我已经测试了,它也写了 Scala Doc
"test " + "1"
所以我的理解是这样的 +
就像Java String +
但 ++
功能更强大,可以采用更多类型的参数。也 ++
似乎是List等其他东西的普遍性。我想知道我的理解是否正确。和其他任何差异?什么时候应该另一个只是为了字符串连接?
它有助于了解一下 scala.Predef
看看究竟发生了什么。
如果你在那里检查,你会看到 String
在Scala只是一个别名 java.lang.String
。换句话说, +
方法 String
被翻译成Java的 +
运营商。
所以,如果是Scala String
只是一个Java String
,怎么样 ++
方法甚至存在,你可能会问。 (好吧,我至少会问。)答案是有一个隐含的转换 String
至 WrappedString
由...提供 wrapString
方法,也在 Predef
。
请注意 ++
接受任何 GenTraversableOnce
实例并将该实例中的所有元素添加到原始元素中 WrappedString
。 (请注意,文档错误地指出该方法返回一个 WrappedString[B]
。这必须是不正确的,因为 WrappedString
不接受类型参数。)你会得到的是a 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所说,这些都不是一个非常微妙的工具,所以你最好不要使用它 字符串插值 或者a StringBuilder
除非有充分理由不这样做。
String
是一个 TraversableLike
,这意味着它可以分解为一系列元素(字符)。那就是 ++
来自,否则你做不到 ++
在字符串上。 ++
仅当它的右侧(或该函数的参数)是可解组合类型(或可遍历)时才会起作用。
现在怎么样 String
成为一个 TraversableLike
?这就是定义中的含义 Predef
参加进来。其中一个隐式转换正常 String
变成一个 WrappedString
哪里 WrappedString.canBuildFrom
拥有基本上以这种方式工作的所有胶水:
WrappedString.canBuildFrom
- > StringBuilder
- > StringLike
- > IndexedSeqOptimized
- > IndexedSeqLike
- > SeqLike
- > IterableLike
- > TraversableLike
由于Predef中定义的implicits已经在范围内,因此可以编写如下代码:
"test " ++ "1"
现在你的问题:
我想知道我的理解是否正确。和其他任何差异?
是的,你的理解是正确的方向。
什么时候应该另一个只是为了字符串连接?
对于字符串连接,很明显 "test " + "1"
创建更少的对象,减少函数调用次数。但是,我总是喜欢字符串插值,如下所示:
val t1 = "test"
val t2 = "1"
val t3 = s"$t1 $t2"
哪个更具可读性。
更多细节:
所以我的理解是+就像Java String +但是++更强大,可以接受更多类型的参数
事情是, +
在这个意义上,字符串更强大:它可以接受任何参数,就像在Java中一样。这通常被认为是错误的(特别是因为它也适用于右边的字符串),但我们几乎坚持它。 ++
正如你所说,是一般的收集方法,更安全("test " ++ 1
不会编译)。
什么时候应该另一个只是为了字符串连接?
我更喜欢 +
。然而,对于许多人(我甚至说最多)使用你想要的东西既不是:使用 字符串插值 代替。
val n = 1
s"test $n"
当然,从中构建一个字符串 许多 零件,使用 StringBuilder
。
++不一定“更强大”,但它通常用作连接/追加操作。但是,它不执行分配。 IE listX ++ y
将附加到listX,但是 i++
不会增加整数i(因为它分配给变量而不是变异)。
这至少是我的理解。我不是斯卡拉专家。
有一个隐含的转换 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]