この記事は、Elixir Advent Calendar 2023 シリーズ14 の20日目です
【本コラムは、5分で読め、5分で試せます】
piacere です、ご覧いただいてありがとございます
下記Erlangモジュール関数を使うと出てくる ~c
文字列って、Elixirのダブルクォート文字列とだいぶ仕様が異なります
今回、それを見分けたり、使い分けるTIPSをまとめておきました
定義
Erlang文字列は、'~'
ないしは ~c"~"
で定義できます
iex> 'abc'
~c"abc"
iex> ~c"abc"
~c"abc"
実は、~c'~'
でも定義できてしまいますw
iex> ~c'abc'
~c"abc"
Elixirのダブルクォート文字列とは別の型
一致しません
iex> 'abc' == "ABC"
false
一致させるには、型変換が必要です
iex> 'abc' == String.to_charlist("abc")
true
iex> List.to_string('abc') == "abc"
true
型チェック
上記 String.to_charlist
の関数名通り、Erlang文字列の実体はリストです
iex> "abc" |> is_binary
true
iex> "abc" |> is_list
false
iex> 'abc' |> is_binary
false
iex> 'abc' |> is_list
true
Erlang文字列がリストなのは、実は関数型ならではの理由があり、Haskellなどの他関数型言語も文字列はリストで定義されており、Erlangもその流儀に則っているだけです
これにより、リスト処理と文字列処理を共通化させるジェネリックなプログラミングが可能となります
しかし、リストは効率性に課題を抱えることが多いため、Elixirでは、敢えてリストを止めて、ビットストリングベースの文字列としています
Erlang文字列はリスト処理できる
ということは、Erlang文字列はリスト処理できるということですね
iex> 'abc' |> hd
97
iex> <<'abc' |> hd>>
"a"
iex> 'abc' |> Enum.split(2)
{~c"ab", ~c"c"}
iex> Enum.zip('abc', 'xyz')
[{97, 120}, {98, 121}, {99, 122}]
iex> Enum.zip('abc', 'xyz') |> Enum.map(fn {a, b} -> {<<a>>, <<b>>} end)
[{"a", "x"}, {"b", "y"}, {"c", "z"}]
最近のErlang関数事情
以前は、Erlang関数はErlang文字列(つまりリスト)のみ対応していました
iex> 'abc' |> :string.split('b')
[~c"a", ~c"c"]
それが最近は、Elixir文字列(つまりビットストリング)も使えるようになっているし、アレコレ混ぜても動きます
iex> "abc" |> :string.split("b")
["a", "c"]
iex> "abc" |> :string.split('b')
["a", "c"]
iex> 'abc' |> :string.split("b")
[~c"a", ~c"c"]
とは言え、Elixirの String
モジュールが充分便利なので、Erlangモジュールを使う機会はあまり無いと思います