Ответы:
Если вы просто хотите присоединиться к произвольному списку:
"StringA" <> " " <> "StringB"
или просто используйте интерполяцию строк:
"#{a} #{b}"
Если размер вашего списка произвольный:
Enum.join(["StringA", "StringB"], " ")
... все решения выше вернутся
"StringA StringB"
Если то, что у вас есть, является произвольным списком, то вы можете использовать Enum.join
, но если это всего лишь два или три, явное сцепление строк должно быть легче для чтения
"StringA" <> " " <> "StringB"
Тем не менее, часто вам не нужно иметь его как одну строку в памяти, если вы собираетесь выводить ее, например, через сеть. В этом случае может быть полезно использовать iolist (определенный тип глубокого списка), который избавляет вас от копирования данных. Например,
iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok
Поскольку вы будете использовать эти строки в качестве переменных где-либо, используя глубокий список, вы избегаете выделения целой новой строки просто для вывода ее в другом месте. Многие функции в эликсире / эрланге понимают иолисты, поэтому вам часто не нужно выполнять дополнительную работу.
Enum.reduce тоже подойдет для вашего примера нет?
iex(4)> Enum.reduce(["StringA", "StringB"], fn(x, acc) -> x <> " " <> acc end)
"StringB StringA"
Это зависит от того, что вы пытаетесь сделать. Если вы просто пытаетесь записать новую переменную, просто используйте либо:
Строковая интерполяция
a = "StringA"
b = "StringB"
"#{a} #{b}"
Конкатенация строк: "StringA" <> " " <> "StringB
Enum.join()
: ["StringA", "StringB"] |> Enum.join(" ")
Однако, как упоминал Ури, списки IOL также могут быть использованы:
["StringA", " ", "StringB"] |> IO.iodata_to_binary
Списки IOL на самом деле будут наиболее эффективными, если вам нужно заботиться о потреблении ресурсов. Big Nerd Ranch имеет хорошую статью о повышении производительности с IOLists.
Существует несколько методов, но знание того, как он обрабатывает нулевые значения, может определить, какой метод вы должны выбрать.
Это выдаст ошибку
iex(4)> "my name is " <> "adam"
"my name is adam"
iex(1)> "my name is " <> nil
** (ArgumentError) expected binary argument in <> operator but got: nil
(elixir) lib/kernel.ex:1767: Kernel.wrap_concatenation/3
(elixir) lib/kernel.ex:1758: Kernel.extract_concatenations/2
(elixir) lib/kernel.ex:1754: Kernel.extract_concatenations/2
(elixir) expanding macro: Kernel.<>/2
iex:1: (file)
Это просто вставит пустую строку "":
iex(1)> "my name is #{nil}"
"my name is "
Как будет это:
iex(3)> Enum.join(["my name is", nil], " ")
"my name is "
Также рассмотрите типы. С <>
вами не получите ни одного бесплатного кастинга:
iex(5)> "my name is " <> 1
** (ArgumentError) expected binary argument in <> operator but got: 1
(elixir) lib/kernel.ex:1767: Kernel.wrap_concatenation/3
(elixir) lib/kernel.ex:1758: Kernel.extract_concatenations/2
(elixir) lib/kernel.ex:1754: Kernel.extract_concatenations/2
(elixir) expanding macro: Kernel.<>/2
iex:5: (file)
iex(5)> "my name is #{1}"
"my name is 1"
iex(7)> Enum.join(["my name is", 1], " ")
"my name is 1"
Производительность на практике кажется примерно одинаковой:
iex(22)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{8023855, :ok}
iex(23)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{8528052, :ok}
iex(24)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is " <> "adam" end) end)
{7778532, :ok}
iex(25)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7620582, :ok}
iex(26)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7782710, :ok}
iex(27)> :timer.tc(fn -> Enum.each(1..10_000_000, fn _ -> "my name is #{"adam"}" end) end)
{7743727, :ok}
Итак, действительно зависит от того, хотите ли вы потерпеть крах или нет, когда интерполированные значения имеют nil
неправильный тип.
Вы могли бы также сделать 'string A' ++ ' ' ++ 'string B'
Попробуйте использовать IO List, если у вас есть ["String1", "string2"] и вы используете в нем iolist_to_binary / 1, тогда вы скопируете эти строки в новую строку. Если у вас есть список ввода-вывода, вы можете просто вывести его в большинстве случаев, и он объединит его с портом. И это главное, во время выполнения не нужно будет делать копии данных, поэтому это намного эффективнее, чем конкатенация.
["StringA", "StringB"] |> Enum.join " "