我是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]。实际上,前两个元素是 Chars,但最后三个是 Strings,如后续电话所示。
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]