11章は文字列。
Elixirで面白いのは、シングルクォートとダブルクォートで全く違うものを表すこと。 ダブルクォートがいわゆる文字列で、シングルクォートは文字コードのリスト。内部表現は全然違う。 というか、ワイルドなことにElixirは文字列として出力可能な整数のリストをシングルクォートで囲まれた文字として出力する。マジカ。
iex> hello = [0x48, 0x65, 0x6c, 0x6c, 0x6f] 'Hello' iex> hello ++ [0] [72, 101, 108, 108, 111, 0] iex> [first |rest] = hello 'Hello' iex> {first, rest} {72, 'ello'}
おもしろい。
次にバイナリ。ビット列の表現で、かなり厳密にビットの並びを表現できる。 さらに、その表現を使ってパターンマッチすることでビットを分割できる。 下はIEEE754倍精度浮動小数点数をフィールドで分解して再構築している例。
iex> << sign::size(1), exp::size(11), mantissa::size(52) >> = << 3.14159::float >> <<64, 9, 33, 249, 240, 27, 134, 110>> iex> (1 + mantissa / :math.pow(2, 52)) * :math.pow(2, exp-1023) * (1 - 2*sign) 3.14159
これはかなり簡潔で凄い。
さて、ダブルクォート文字列は内部的にUTF-8のバイト列としてバイナリに格納されている。 つまり、リストではない。そして、バイト列としての長さと、文字列の長さはまったく別である。
iex> s_and_b = "寿司🍣ビール🍺" "寿司🍣ビール🍺" iex> String.length s_and_b 7 iex> byte_size s_and_b 23 iex> String.codepoints(s_and_b) ["寿", "司", "🍣", "ビ", "ー", "ル", "🍺"]
String.codepointsとString.graphemesの違いの説明あり。 コードポイントと書記素は違うもの。この辺がちゃんと用意されているのが新しい言語だなーと思う。
iex> 日米対決 = "🇯🇵VS🇺🇸" "🇯🇵VS🇺🇸" iex> String.codepoints 日米対決 ["🇯", "🇵", "V", "S", "🇺", "🇸"] iex> String.graphemes 日米対決 ["🇯🇵", "V", "S", "🇺🇸"]
そして、リストじゃないので[ car | cdr ]
ではパターンマッチできない。
代わりに<< head :: utf8, tail :: binary>>
を使う。