Câu trả lời:
Nếu bạn chỉ muốn tham gia một số danh sách tùy ý:
"StringA" <> " " <> "StringB"
hoặc chỉ sử dụng phép nội suy chuỗi:
"#{a} #{b}"
Nếu kích thước danh sách của bạn là tùy ý:
Enum.join(["StringA", "StringB"], " ")
... tất cả các giải pháp trên sẽ trở lại
"StringA StringB"
Nếu những gì bạn có là một danh sách tùy ý, thì bạn có thể sử dụng Enum.join
, nhưng nếu nó chỉ dành cho hai hoặc ba, thì việc nối chuỗi rõ ràng sẽ dễ đọc hơn
"StringA" <> " " <> "StringB"
Tuy nhiên, thường thì bạn không cần phải có một chuỗi trong bộ nhớ nếu bạn định xuất nó qua mạng. Trong trường hợp đó, có thể thuận lợi khi sử dụng iolist (một loại cụ thể của danh sách sâu), giúp bạn tiết kiệm từ việc sao chép dữ liệu. Ví dụ,
iex(1)> IO.puts(["StringA", " ", "StringB"])
StringA StringB
:ok
Vì bạn sẽ có các chuỗi đó dưới dạng các biến ở đâu đó, bằng cách sử dụng một danh sách sâu, bạn tránh phân bổ một chuỗi hoàn toàn mới chỉ để xuất nó ở nơi khác. Nhiều chức năng trong elixir / erlang hiểu iolists, vì vậy bạn thường không cần phải làm thêm.
Một Enum.reduce sẽ làm việc quá cho ví dụ của bạn không?
iex(4)> Enum.reduce(["StringA", "StringB"], fn(x, acc) -> x <> " " <> acc end)
"StringB StringA"
Nó phụ thuộc vào những gì bạn đang cố gắng làm. Nếu bạn chỉ đang cố gắng viết ra một biến mới, thì chỉ cần sử dụng một trong hai:
Nội suy chuỗi
a = "StringA"
b = "StringB"
"#{a} #{b}"
Chuỗi kết nối: "StringA" <> " " <> "StringB
Enum.join()
: ["StringA", "StringB"] |> Enum.join(" ")
Tuy nhiên, như Uri đã đề cập, IOLists cũng có thể được sử dụng:
["StringA", " ", "StringB"] |> IO.iodata_to_binary
IOLists thực sự sẽ là người thực hiện nhiều nhất nếu bạn cần quan tâm đến việc tiêu thụ tài nguyên. Big Nerd Ranch có một bài viết tốt về hiệu suất đạt được w / IOLists.
Có một số phương thức, nhưng biết cách nó xử lý các giá trị nil có thể xác định phương thức nào bạn nên chọn.
Điều này sẽ gây ra lỗi
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)
Điều này sẽ chỉ chèn một chuỗi "" trống:
iex(1)> "my name is #{nil}"
"my name is "
Như thế này:
iex(3)> Enum.join(["my name is", nil], " ")
"my name is "
Cũng xem xét các loại. Với <>
bạn không nhận được bất kỳ casting miễn phí:
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"
Hiệu suất trong thực tế có vẻ gần giống nhau:
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}
Vì vậy, thực sự phụ thuộc vào việc bạn có muốn sụp đổ hay không khi các giá trị nội suy là nil
hoặc loại sai.
Cân nhắc sử dụng Danh sách IO, nếu bạn có ["String1", "string2"] và bạn sử dụng iolist_to_binary / 1 trên đó thì bạn sẽ sao chép các chuỗi đó thành một chuỗi mới. Nếu bạn có một danh sách IO, bạn có thể chỉ cần xuất nó trong hầu hết các trường hợp và nó sẽ nối nó trên cổng. Và đây là điều quan trọng, thời gian chạy sẽ không cần tạo các bản sao của dữ liệu để nó hiệu quả hơn nhiều so với ghép nối.
["StringA", "StringB"] |> Enum.join " "