プログラミング Elixir 第四章


概要

プログラミング Elixir

型や変数の命名規則、演算子、スコープなど、変数の基本的な知識を解説している章。

値型

整数

10, 16, 8 , 2 進数で表すことができる。10 進数では、数値の区切りに _ を使用できる。
決まった最大値はない。

浮動小数点数

小数点で表す。小数点の前後に少なくとも 1 つ数値を書かなければいけない。
指数も追記することができる 0.314e1。 IEEE 754 倍精度(double) 16 桁程度の正確さを持つ。

アトム

コロン(:)で始まる、名前を表現する定数。アルファベット, 数字, _, @ を使用可能で、末尾に !, ? を使うことができる。ダブルクォートで囲むと任意の文字を使用できる。

:taro, :is_taro?, :"he is taro"

同じ値のアトムは比較すると必ず同じになる。

範囲

start..end で表す。start, end は整数。

正規表現

~r{regexp}opts のように表す。opts はオプション指定する場合に書く(docs 参照)。
区切り文字には {} 以外でもアルファベット文字以外は使用できる // など。ただし、// を使用すると正規表現内に / が含まれる場合エスケープする必要がある。

iex> Regex.match?(~r{taro}, "yamada taro")
=> true
iex> Regex.match?(~r{taro}i, "Yamada Taro")
=> true

システム型

PID・ポート

PID はローカル・リモートプロセスへの参照で、ポートは読み書きするリソースへの参照。
カレントプロセスの PID は self で取得ができ、新しい PID は新しいプロセスを生成した時に作られる。

リファレンス

make_ref でグローバルに一意なリファレンスを生成する。

コレクション型

タプル

順序を持ったコレクション。{} で囲む。

{:a, :b, :c}
{1, 2}

関数でエラーが無いときに、第一要素に :ok というアトムを持つタプルを返すことをよくやる。

iex> {status, file} = File.open('log.txt')
=> {:ok, #PID<0.82.0>}

これを利用して、成功を仮定したマッチを書くのに使う

iex> {:ok, file} = File.open('no_exist.txt')
** (MatchError) no match of right hand side value: {:error, :enoent}

リスト

[1, 2, 3] のように書く。
他言語での配列ではなく、連結データ構造になっており、一つの head(先頭要素)と一つの tail(それ以降)からなる。head は一つの値を持ち、tail はリストになっている。これは再帰的な処理を書く際の核となる。

また、幾つかリストのための演算子がある。

iex> [1, 2] ++ [3, 4, 5]
=> [1, 2, 3, 4, 5]

iex> [1, 2, 3] -- [3, 4, 5]
=> [1, 2]

iex> 1 in [1, 2, 3]
=> true

キーワードリスト

[a: 1, b: 2, c: 3] のように、キーと値のペアのリストを書く事ができる。

一見 Ruby の Hash のように見えるが、Ruby の Hash に近いものは次に紹介するマップで表す。
キーワードリストは、内部で 2 つの要素を持つタプルのリストに変換され、[{:a, 1}, {:b, 2}, {:c, 3}] と同じ意味である。

iex> [a: 1, b: 2, c: 3] === [{:a, 1}, {:b, 2}, {:c, 3}]
=> true

マップ

キーと値のペアのコレクション。以下の様に書く。

%{key => value, key => value}

キーは文字列、タプル、アトムと様々なものを使用することができる。

iex> %{'name' => 'taro'}
=> %{'name' => 'taro'}

iex> %{{'name', 'namae'} => 'taro'}
=> %{{'name', 'namae'} => 'taro'}

iex> %{:name => 'taro'}
=> %{name: 'taro'}

キーの型は異なって良い

iex> %{:name => 'taro', 'address' => 'Tokyo', {:tel, :fax} => '000-1111-2222' }
=> %{:name => 'taro', {:tel, :fax} => '000-1111-2222', 'address' => 'Tokyo'}

式も使うことができる

iex> %{String.downcase("NAME") <> "_1" => 'taro'}
%{"name_1" => 'taro'}

キーワードリストと違い、同じキーを許さない

iex> %{name: 1, name: 2}
=> %{name: 2}

一般的に、キーワードリストはコマンドラインパラメーターやオプションの受け渡し、マップは連想配列が欲しい場合に使う。

マップの値の取り出し方は以下のようにする。

iex> nums = %{'a' => 1, 'b' => 2, 'c' => 3}
=> %{'a' => 1, 'b' => 2, 'c' => 3}

iex> nums['a']
=> 1

キーがアトムの場合はドットで取得できる

iex> nums = %{a: 1, b: 2, c: 3}
=> %{a: 1, b: 2, c: 3}

iex> nums.a
=> 1

バイナリ

<< >> で囲うとバイナリ型となる。

iex> bin = <<1, 2>>
=> <<1, 2>>

iex> byte_size bin
=> 2

名前

Elixir の識別子には、大文字・小文字の ASCII 文字、数字、アンダースコアで構成される。末尾には !, ? を使用できる。

モジュール、レコード、プロトコル、ビヘイビアは大文字始まりのキャメルケースで表される。その他の識別子は全て、小文字かアンダースコアで始まるスネークケースで表す。
アンダースコアで、その変数が使われないことを表明している。

その他、慣習などはスタイルガイドにまとまっている。

真偽値

Elixir にはブール演算のために true, false, nil の特別な値を用意している。
nil はブール演算において false を表す。

変数スコープ

Elixir はレキシカルスコープになっており、スコープの基本単位は関数である。
関数内で定義された変数は関数内でしか参照できない。また、モジュール内に変数を定義した場合は、そのモジュールのトップレベルからアクセスできず、関数からアクセスすることはできない。

with

with を使えば、上記とは別に独自スコープを定義することができる。

iex> a = 'hoge'
=> 'hoge'
iex> b = with a = 'fuga', do: a
=> 'fuga'
iex> a
=> 'hoge'

with 式内で a'fuga' を束縛しているが、外側の a には影響していない。

以上が Elixir の基本的な変数の型と扱いである。