Risposte:
Se vuoi solo unirti ad un elenco arbitrario:
"StringA" <> " " <> "StringB"
o usa semplicemente l'interpolazione di stringhe:
"#{a} #{b}"
Se la dimensione dell'elenco è arbitraria:
Enum.join(["StringA", "StringB"], " ")
... tutte le soluzioni sopra riportate torneranno
"StringA StringB"
Se quello che hai è un elenco arbitrario, allora puoi usare Enum.join
, ma se è solo per due o tre, la concatenazione di stringhe esplicite dovrebbe essere più facile da leggere
"StringA" <> " " <> "StringB"
Tuttavia, spesso non è necessario averlo come singola stringa in memoria se lo si desidera generare attraverso, ad esempio, la rete. In tal caso, può essere vantaggioso utilizzare una iolist (un tipo specifico di un elenco approfondito), che consente di risparmiare dalla copia dei dati. Per esempio,
iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok
Dal momento che dovresti avere quelle stringhe come variabili da qualche parte, usando un elenco profondo, eviti di allocare una stringa completamente nuova solo per produrla altrove. Molte funzioni di elisir / erlang comprendono gli iolisti, quindi spesso non dovresti fare il lavoro extra.
Un Enum.reduce funzionerebbe anche per il tuo esempio no?
iex(4)> Enum.reduce(["StringA", "StringB"], fn(x, acc) -> x <> " " <> acc end)
"StringB StringA"
Dipende da cosa stai cercando di fare. Se stai solo cercando di scrivere su una nuova variabile, usa semplicemente:
Interpolazione di stringhe
a = "StringA"
b = "StringB"
"#{a} #{b}"
Concatenazione di stringhe: "StringA" <> " " <> "StringB
Enum.join()
: ["StringA", "StringB"] |> Enum.join(" ")
Tuttavia, come menzionato da Uri, gli IOList possono anche essere usati:
["StringA", " ", "StringB"] |> IO.iodata_to_binary
Gli IOList saranno effettivamente i più performanti se hai bisogno di preoccuparti del consumo di risorse. Big Nerd Ranch ha una buona descrizione degli aumenti delle prestazioni con IOLists.
Esistono diversi metodi, ma sapere come gestisce valori nulli può determinare quale metodo scegliere.
Questo genererà un errore
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)
Questo inserirà semplicemente una "" stringa vuota:
iex(1)> "my name is #{nil}"
"my name is "
Come sarà questo:
iex(3)> Enum.join(["my name is", nil], " ")
"my name is "
Considera anche i tipi. Con <>
te non ricevi nessun casting gratuito:
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"
Le prestazioni in pratica sembrano all'incirca le stesse:
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}
Quindi, dipende davvero se vuoi andare in crash o meno quando i valori interpolati sono nil
o il tipo sbagliato.
Prendi in considerazione l'utilizzo di un Elenco IO, se hai ["String1", "string2"] e usi iolist_to_binary / 1 su di esso, copierai quelle stringhe in una nuova stringa. Se si dispone di un elenco IO, è possibile emetterlo nella maggior parte dei casi e lo concatenerà sulla porta. E questa è la cosa chiave, il runtime non avrà bisogno di fare copie dei dati, quindi è molto più efficiente della concatenazione.
["StringA", "StringB"] |> Enum.join " "