Scala: Строка "+" против "++"
Я новичок в Scala, и я видел код для конкатенации строк в Scala следующим образом:
"test " ++ "1"
И я проверил, и он также написан в Scala Doc
"test " + "1"
Итак, я понимаю, что +
подобен Java String +
, но ++
более мощный, может принимать больше типов параметров. Также ++
кажется универсальным для других вещей, таких как List. Я хочу знать, правильно ли я понимаю. и любые другие различия? Когда нужно один над другим только для конкатенации строк?
Ответы
Ответ 1
Это помогает взглянуть на scala.Predef
, чтобы увидеть, что именно происходит.
Если вы проверите там, вы увидите, что String
в Scala - это просто псевдоним для java.lang.String
. Другими словами, метод +
в String
переводится в оператор Java +
.
Итак, если Scala String
- это просто Java String
, как вообще существует метод ++
, спросите вы. (Ну, я бы спросил, по крайней мере.) Ответ заключается в том, что существует неявное преобразование из String
в WrappedString
, обеспечиваемое методом wrapString
, который также находится в Predef
.
Обратите внимание, что ++
берет любой экземпляр GenTraversableOnce
и добавляет все элементы этого экземпляра к исходному WrappedString
. (Обратите внимание, что в документах неверно указано, что метод возвращает WrappedString[B]
. Это должно быть неверно, поскольку WrappedString
не принимает параметры типа.) Что вы получите, так это либо String
(если вы add - это Seq[Char]
) или какой-то IndexedSeq[Any]
(если это не так).
Вот несколько примеров:
Если вы добавите String
к List[Char]
, вы получите строку.
scala> "a" ++ List('b', 'c', 'd')
res0: String = abcd
Если вы добавите String
к List[String]
, вы получите IndexedSeq[Any]
. На самом деле, первые два элемента - это Char
, но последние три - это String
, как показывает следующий вызов.
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
Как отметил Алексей, ни один из них не является очень тонким инструментом, поэтому вам, вероятно, лучше использовать строковую интерполяцию или StringBuilder
, если только для этого нет веской причины не,
Ответ 2
String
- это TraversableLike
, что означает, что его можно разложить на последовательность элементов (символов). Вот откуда приходит ++
, иначе вы не можете сделать ++
в String. ++
будет работать только тогда, когда его правая сторона (или параметр этой функции) является декомпозиционным типом (или проходящим).
Теперь как String
станет TraversableLike
? Это означает, что вступают в действие те, которые определены в Predef
. Один из неявных преобразует нормальный String
в WrappedString
, где WrappedString.canBuildFrom
имеет весь клей, который в основном работает таким образом:
WrappedString.canBuildFrom
→ StringBuilder
→ StringLike
→ IndexedSeqOptimized
→ IndexedSeqLike
→ SeqLike
→ IterableLike
→ TraversableLike
Так как implitsits, определенные в Predef, уже находятся в области видимости, можно написать такой код:
"test " ++ "1"
Теперь ваши вопросы:
Я хочу знать, правильно ли я понимаю. и любые другие различия?
Да, ваше понимание в правильном направлении.
Когда нужно один над другим только для конкатенации строк?
Для конкатенации строк ясно, что "test " + "1"
создает меньше объектов и меньше числа вызовов функций. Тем не менее, я всегда предпочитал бы интерполяцию строк так:
val t1 = "test"
val t2 = "1"
val t3 = s"$t1 $t2"
что более читаемо.
Подробнее:
Ответ 3
Итак, я понимаю, что + похож на Java String +, но ++ более мощный, может принимать больше типов параметров
Дело в том, что +
на Strings является более мощным в этом смысле: он может принимать любые параметры вообще, как и в Java. Это часто считается недостоверным (особенно потому, что он также работает со строками справа), но мы в значительной степени застряли в нем. ++
- это, как вы говорите, общий метод сбора и более безопасный тип ("test " ++ 1
не будет компилироваться).
Когда нужно один над другим только для конкатенации строк?
Я бы предпочел +
. Тем не менее, для многих (я бы даже сказал, большинство), что вы не хотите, не используйте: строчную интерполяцию.
val n = 1
s"test $n"
И, конечно, при создании строки из многих частей используйте StringBuilder
.
Ответ 4
++ не обязательно "более мощный", но он используется в целом как операция конкатенации/добавления. Однако он не выполняет назначение. IE listX ++ y
будет добавляться в listX, но i++
не будет увеличивать целое число я (поскольку это назначает переменной в сравнении с мутированием).
Это, по крайней мере, мое понимание. Я не эксперт Scala.
Ответ 5
Существует неявное преобразование от 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]