Scala:字符串“+”与“++”
Scala: String "+" vs "++"
我是 Scala 的新手,我已经看到在 Scala 中连接字符串的代码如下:
"test " ++ "1"
而且我测试过,也是写在Scala Doc
"test " + "1"
所以我的理解是 +
就像 Java String +
但是 ++
更强大,可以接受更多类型的参数。 ++
似乎也适用于 List 等其他事物。我想知道我的理解是否正确。还有其他区别吗?什么时候应该一个接一个只是为了字符串连接?
So my understanding is that + is like the Java String + but ++ is more powerful, can take in more types of parameters
问题是,+
on Strings 在这个意义上更强大:它可以接受任何参数,就像 Java 一样。这通常被认为是一个错误功能(特别是因为它也适用于右侧的字符串),但我们几乎坚持使用它。正如您所说,++
是一种通用的收集方法,并且类型更安全("test " ++ 1
无法编译)。
When should one over another just for string concatenation?
我更喜欢 +
。但是,对于许多(我什至会说大多数)用法,您想要的都不是:改用 string interpolation。
val n = 1
s"test $n"
当然,当从 多个 部分构建字符串时,请使用 StringBuilder
.
++ 不一定是 "more powerful",但它通常用作 concatenation/appending 操作。但是,它不执行分配。 IE listX ++ y
将附加到 listX,但 i++
不会增加整数 i(因为这是分配给变量而不是变异)。
至少这是我的理解。我不是 Scala 专家。
在 scala.Predef
中存在从 String
到 StringOps
的隐式转换。 ++
方法在StringOps
class 中定义。因此,每当您执行 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]
查看 scala.Predef
以了解到底发生了什么会有所帮助。
如果你在那里查看,你会发现 Scala 中的 String
只是 java.lang.String
的别名。换句话说,String
上的 +
方法被翻译成 Java 的 +
运算符。
所以,如果 Scala String
只是一个 Java String
,那么 ++
方法是如何存在的,您可能会问。 (好吧,至少我会问。)答案是 wrapString
方法提供了从 String
到 WrappedString
的隐式转换,它也在 Predef
.
请注意,++
采用任何 GenTraversableOnce
实例并将该实例中的所有元素添加到原始 WrappedString
。 (请注意,文档错误地指出方法 returns 是 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 or a StringBuilder
除非有充分的理由不这样做。
String
是一个TraversableLike
,表示可以分解成一个元素序列(字符)。这就是 ++
的来源,否则你不能对 String 做 ++
。 ++
仅当它的右侧(或该函数的参数)是可分解类型(或可遍历类型)时才有效。
现在 String
是如何变成 TraversableLike
的?这就是 Predef
中定义的隐含函数发挥作用的地方。其中一个隐式将正常 String
转换为 WrappedString
,其中 WrappedString.canBuildFrom
具有基本上以这种方式工作的所有胶水:
WrappedString.canBuildFrom
-> StringBuilder
-> StringLike
-> IndexedSeqOptimized
-> IndexedSeqLike
-> SeqLike
-> IterableLike
-> TraversableLike
由于 Predef 中定义的隐式已经在范围内,因此可以编写如下代码:
"test " ++ "1"
现在你的问题:
I want to know if my understanding is correct. and any other differences?
是的,你的理解是正确的。
When should one over another just for string concatenation?
对于字符串连接,显然 "test " + "1"
创建的对象更少,函数调用的次数也更少。但是,我总是更喜欢这样的字符串插值:
val t1 = "test"
val t2 = "1"
val t3 = s"$t1 $t2"
哪个更具可读性。
更多详情:
我是 Scala 的新手,我已经看到在 Scala 中连接字符串的代码如下:
"test " ++ "1"
而且我测试过,也是写在Scala Doc
"test " + "1"
所以我的理解是 +
就像 Java String +
但是 ++
更强大,可以接受更多类型的参数。 ++
似乎也适用于 List 等其他事物。我想知道我的理解是否正确。还有其他区别吗?什么时候应该一个接一个只是为了字符串连接?
So my understanding is that + is like the Java String + but ++ is more powerful, can take in more types of parameters
问题是,+
on Strings 在这个意义上更强大:它可以接受任何参数,就像 Java 一样。这通常被认为是一个错误功能(特别是因为它也适用于右侧的字符串),但我们几乎坚持使用它。正如您所说,++
是一种通用的收集方法,并且类型更安全("test " ++ 1
无法编译)。
When should one over another just for string concatenation?
我更喜欢 +
。但是,对于许多(我什至会说大多数)用法,您想要的都不是:改用 string interpolation。
val n = 1
s"test $n"
当然,当从 多个 部分构建字符串时,请使用 StringBuilder
.
++ 不一定是 "more powerful",但它通常用作 concatenation/appending 操作。但是,它不执行分配。 IE listX ++ y
将附加到 listX,但 i++
不会增加整数 i(因为这是分配给变量而不是变异)。
至少这是我的理解。我不是 Scala 专家。
在 scala.Predef
中存在从 String
到 StringOps
的隐式转换。 ++
方法在StringOps
class 中定义。因此,每当您执行 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]
查看 scala.Predef
以了解到底发生了什么会有所帮助。
如果你在那里查看,你会发现 Scala 中的 String
只是 java.lang.String
的别名。换句话说,String
上的 +
方法被翻译成 Java 的 +
运算符。
所以,如果 Scala String
只是一个 Java String
,那么 ++
方法是如何存在的,您可能会问。 (好吧,至少我会问。)答案是 wrapString
方法提供了从 String
到 WrappedString
的隐式转换,它也在 Predef
.
请注意,++
采用任何 GenTraversableOnce
实例并将该实例中的所有元素添加到原始 WrappedString
。 (请注意,文档错误地指出方法 returns 是 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 or a StringBuilder
除非有充分的理由不这样做。
String
是一个TraversableLike
,表示可以分解成一个元素序列(字符)。这就是 ++
的来源,否则你不能对 String 做 ++
。 ++
仅当它的右侧(或该函数的参数)是可分解类型(或可遍历类型)时才有效。
现在 String
是如何变成 TraversableLike
的?这就是 Predef
中定义的隐含函数发挥作用的地方。其中一个隐式将正常 String
转换为 WrappedString
,其中 WrappedString.canBuildFrom
具有基本上以这种方式工作的所有胶水:
WrappedString.canBuildFrom
-> StringBuilder
-> StringLike
-> IndexedSeqOptimized
-> IndexedSeqLike
-> SeqLike
-> IterableLike
-> TraversableLike
由于 Predef 中定义的隐式已经在范围内,因此可以编写如下代码:
"test " ++ "1"
现在你的问题:
I want to know if my understanding is correct. and any other differences?
是的,你的理解是正确的。
When should one over another just for string concatenation?
对于字符串连接,显然 "test " + "1"
创建的对象更少,函数调用的次数也更少。但是,我总是更喜欢这样的字符串插值:
val t1 = "test"
val t2 = "1"
val t3 = s"$t1 $t2"
哪个更具可读性。
更多详情: