斯卡拉:弦"+"与"++"


我是 Scala

的新手,我见过在 Scala 中连接字符串的代码,如下所示:

"test " ++ "1"

我已经测试过了,它也用 Scala 文档编写

"test " + "1"

所以我的理解是,+就像Java字符串+ ++但功能更强大,可以接受更多类型的参数。此外,++似乎对列表等其他事物具有通用性。我想知道我的理解是否正确。还有其他区别吗?什么时候应该只为了字符串连接而一个?

看看

scala.Predef看看到底发生了什么,会很有帮助。

如果你在那里检查,你会发现 Scala 中的String只是 java.lang.String 的别名。换句话说,String上的+方法被转换为Java的+运算符。

所以,如果一个Scala String只是一个Java String,你可能会问++方法是如何存在的。(好吧,至少我会问。答案是,wrapString 方法提供了从 StringWrappedString 的隐式转换,这也是Predef .

请注意,++ 采用任何GenTraversableOnce实例,并将该实例中的所有元素添加到原始WrappedString 中。(请注意,文档错误地指出该方法返回WrappedString[B]。这必须是不正确的,因为WrappedString不接受类型参数。你会得到的要么是String(如果你添加的东西是Seq[Char](要么是一些IndexedSeq[Any](如果不是(。

以下是一些示例:

如果将String添加到List[Char],则会得到一个字符串。

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

如果向List[String]添加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 所指出的,这些都不是一个非常微妙的工具,所以你最好使用字符串插值或StringBuilder,除非有充分的理由不这样做。

String是一个TraversableLike,这意味着它可以分解成一系列元素(字符(。这就是++的来源,否则你不能在字符串上做++++只有在它的右侧(或该函数的参数(是可分解类型(或可遍历(时才有效。

现在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"

哪个更具可读性。

有关更多详细信息:

  • Scala 源代码:https://github.com/scala/scala
  • http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html

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

问题是,从

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

什么时候应该只为了字符串连接而一个?

我更喜欢+.但是,对于许多(我什至会说大多数(用法,您想要的两者都不是:使用字符串插值代替。

val n = 1
s"test $n"

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

++不一定

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

至少这是我的理解。 我不是 Scala 专家。

scala.Predef 中有一个从 StringStringOps 的隐式转换。++ 方法在 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]

相关内容

  • 没有找到相关文章

最新更新