Tambourine作業メモ

主にスキル習得のためにやった作業のメモ。他人には基本的に無用のものです。

Elixirで遊んでみる(7)

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>>を使う。