Jawaban:
Jika Anda hanya ingin bergabung dengan beberapa daftar arbitrer:
"StringA" <> " " <> "StringB"
atau cukup gunakan interpolasi string:
"#{a} #{b}"
Jika ukuran daftar Anda arbitrer:
Enum.join(["StringA", "StringB"], " ")
... semua solusi di atas akan kembali
"StringA StringB"
Jika yang Anda miliki adalah daftar arbitrer, maka Anda dapat menggunakannya Enum.join
, tetapi jika hanya untuk dua atau tiga, rangkaian string eksplisit harus lebih mudah dibaca
"StringA" <> " " <> "StringB"
Namun, sering kali Anda tidak perlu memilikinya sebagai string tunggal dalam memori jika Anda akan mengeluarkannya melalui misalnya jaringan. Dalam hal ini, akan menguntungkan untuk menggunakan iolist (tipe spesifik dari daftar yang mendalam), yang menyelamatkan Anda dari menyalin data. Sebagai contoh,
iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok
Karena Anda akan memiliki string tersebut sebagai variabel di suatu tempat, dengan menggunakan daftar yang mendalam, Anda menghindari mengalokasikan string yang sama sekali baru hanya untuk output di tempat lain. Banyak fungsi di elixir / erlang mengerti iolists, jadi Anda seringkali tidak perlu melakukan pekerjaan ekstra.
Sebuah Enum.reduce akan bekerja juga untuk contoh Anda, tidak?
iex(4)> Enum.reduce(["StringA", "StringB"], fn(x, acc) -> x <> " " <> acc end)
"StringB StringA"
Itu tergantung pada apa yang Anda coba lakukan. Jika Anda hanya mencoba menulis ke variabel baru, gunakan saja:
Interpolasi string
a = "StringA"
b = "StringB"
"#{a} #{b}"
String concatentation: "StringA" <> " " <> "StringB
Enum.join()
: ["StringA", "StringB"] |> Enum.join(" ")
Namun, seperti yang disebutkan Uri, IOLists juga dapat digunakan:
["StringA", " ", "StringB"] |> IO.iodata_to_binary
IOLists sebenarnya akan menjadi yang paling berprestasi jika Anda perlu peduli dengan konsumsi sumber daya. Peternakan Big Nerd memiliki artikel bagus tentang peningkatan kinerja dengan IOLists.
Ada sejumlah metode, tetapi mengetahui bagaimana menangani nilai nil dapat menentukan metode mana yang harus Anda pilih.
Ini akan menimbulkan kesalahan
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)
Ini hanya akan memasukkan string "" kosong:
iex(1)> "my name is #{nil}"
"my name is "
Seperti ini:
iex(3)> Enum.join(["my name is", nil], " ")
"my name is "
Juga pertimbangkan jenis. Dengan <>
Anda tidak mendapatkan casting gratis:
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"
Kinerja dalam praktik tampaknya kurang lebih sama:
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}
Jadi, sangat tergantung pada apakah Anda ingin crash atau tidak ketika nilai yang diinterpolasi adalah nil
atau tipe yang salah.
Pertimbangkan untuk menggunakan Daftar IO, jika Anda memiliki ["String1", "string2"] dan Anda menggunakan iolist_to_binary / 1 di atasnya maka Anda akan menyalin string tersebut ke string baru. Jika Anda memiliki daftar IO, Anda bisa menampilkannya dalam banyak kasus dan akan menggabungkannya di port. Dan ini adalah kuncinya, runtime tidak perlu membuat salinan data sehingga jauh lebih efisien daripada penggabungan.
["StringA", "StringB"] |> Enum.join " "