Elixirとは
- 分散並列処理に強い言語
- スケールしやすい
- クラッシュからの復帰が容易
- 詳しくは[翻訳] Elixir - 次に来る大物Web言語が分かりやすくて良い
インストール
macの場合はbrewが簡単です。
brew update
brew install elixir
他のOSは公式サイト参照でお願いします。
Interactive Elixir
ターミナルで
iex
と入力するとInteractive Elixirが起動する。PythonやRuby、Rとかにもあるアレ。
Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.7.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
1行目はErlangの情報。このInteractive Elixirを使って色々試していきます。
型
なんか説明怪しいな?と思ったらドキュメントを見るかコメントお願いします。
数値
普通にできそうなことはできる。
iex(1)> 12345
12345
iex(2)> 123+45
168
iex(3)> 123*45
5535
iex(4)> 12/3
4.0
割り算の結果は常にFloat。
i ~~
とすることで型情報などが確認できる。
iex(5)> i 123
Term
123
Data type
Integer
Reference modules
Integer
Implemented protocols
IEx.Info, Inspect, String.Chars, List.Chars
iex(6)> i 12/2
Term
6.0
Data type
Float
Reference modules
Float
Implemented protocols
IEx.Info, Inspect, String.Chars, List.Chars
割り算の結果が整数で欲しい時はdiv/2
を使用。この/2
というのは引数が2個という意味。
iex(7)> div(12/3)
** (CompileError) iex:7: undefined function div/1
iex(7)> div(12,3)
4
iex(8)> div(12,5)
2
iex(9)> div(14,5)
2
端数は切り捨てである。余りを求めたい場合はrem/2
を使う。
iex(10)> rem(12,5)
2
iex(11)> rem(14,5)
4
16進数・2進数が使用できたりする。_
は無視されるので0の多い数字を入力するときに分かりやすくできる。
iex(12)> 0xff
255
iex(13)> 0x63 + 0x63
198
iex(14)> 0b1111 + 0x0F
30
iex(15)> 1.5e4
1.5e4
iex(16)> 1.0e2
100.0
iex(17)> 1_0000_0000
100000000
(追記)8進数も利用できる。
iex(1)> 0o66
54
あとIntegerは最大値がなく、メモリがなくなるまで使える。
iex(18)> 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
iex(19)> i 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Term
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Data type
Integer
Reference modules
Integer
Implemented protocols
IEx.Info, Inspect, String.Chars, List.Chars
Atom
:atom
のように文字列の前に:
を付けたもの。名前と値が同じになる。つまり:atom
の値はatom
だし、:ok
の値はok
となる。
iex(20)> :ok
:ok
iex(21)> i :ok
Term
:ok
Data type
Atom
Reference modules
Atom
Implemented protocols
IEx.Info, Inspect, String.Chars, List.Chars
イマイチ理解できなかったけど、多分同じ文字が同じアドレスを指すようになっているのだと思う。本来文字列同士が同じものか確かめるには1文字ずつチェックする必要があったが、Atomを使えば同じアドレスを指しているかどうかを判定するだけですむ。
iex(22)> :"hogehoge fugafuga"
:"hogehoge fugafuga"
↑空白を入れたい時は""でくくる。
文字列
UTF-8でエンコードされたバイナリ。
iex(23)> thinking_face = "🤔"
"🤔"
iex(24)> i thinking_face
Term
"🤔"
Data type
BitString
Byte size
4
Description
This is a string: a UTF-8 encoded binary. It's printed surrounded by
"double quotes" because all UTF-8 encoded codepoints in it are printable.
Raw representation
<<240, 159, 164, 148>>
Reference modules
String, :binary
Implemented protocols
IEx.Info, Inspect, String.Chars, List.Chars, Collectable
Byte sizeが4となっているがString.length/1
は正しく1文字と判定してくれる。
iex(25)> String.length(thinking_face)
1
iex(26)> "hoge:" + "fuga"
** (ArithmeticError) bad argument in arithmetic expression: "hoge:" + "fuga"
:erlang.+("hoge:", "fuga")
iex(26)> "hoge:" <> "fuga"
"hoge:fuga"
文字列の結合は+
ではなく<>
。
iex(27)> "thinking_face is -> #{thinking_face}"
"thinking_face is -> 🤔"
Javascriptのテンプレートリテラルみたいな埋め込みは#{変数名}
で可能。
iex(1)> "hoge
...(1)> hoge
...(1)> hoge"
"hoge\nhoge\nhoge"
↑入力中に改行もできる。
Tuple
Pythonでは()
でしたがElixirでは{}
で括る。
iex(28)> tuple = {1, :two, "three"}
{1, :two, "three"}
iex(29)> {one, two, three} = tuple
{1, :two, "three"}
iex(30)> one
1
iex(31)> two
:two
iex(32)> three
"three"
型はバラバラでOK。分割代入も可能。特定の要素だけが欲しい時はelem/2
や_
を使う。
iex(33)> elem(tuple, 1)
:two
iex(34)> {first, _, third} = tuple
{1, :two, "three"}
iex(35)> first
1
iex(36)> _
** (CompileError) iex:36: invalid use of _. "_" represents a value to be ignored in a pattern and cannot be used in expressions
iex(36)> third
"three"
_
に代入された値は自動的に破棄される。この_
の使い方はSwiftやKotlin、Goといった比較的新しい言語でよく使用されているもの。最近C#も出来るようになったとか?
Tupleは基本的に変更出来ない。Tupleを修正したければ要素を変えた新しいTupleを作成する。要素を操作したい場合はTupleではなくListやMapを使用する。
集合
List
Listは[]
で表します。
iex(37)> list = [1, :two, "three"]
[1, :two, "three"]
これも型はバラバラでOK。
配列ではなくListなので特定の要素にアクセスするのにO(n)時間かかる。要素を先頭に追加するのはO(1)ですむけど末尾への追加はO(n)なので注意。
【追記】
Listの連結には++
を使う。
iex(54)> list = list ++ [4]
[1, :two, "three", 4]
iex(56)> [0] ++ list
[0, 1, :two, "three", 4]
なんと--
を使うとListの引き算も可能。存在しない値を引いても大丈夫。
iex(57)> ["foo", :bar, 42] -- [42, "bar"]
["foo", :bar]
【追記終】
分割代入もできる。
iex(38)> [one, two, three] = list
[1, :two, "three"]
iex(39)> one
1
iex(40)> two
:two
iex(41)> three
"three"
ただし↑のやつはListの個数が揃っている必要がある。
iex(43)> [hoge, fuga | rest] = list
[1, 2, 3, 4, 5]
iex(44)> hoge
1
iex(45)> fuga
2
iex(46)> rest
[3, 4, 5]
↑先頭の何要素かだけを取り出したい場合は|
を使う。
iex(47)> list = [{:a, 1}, {:b, 2}, {:a, 3}]
[a: 1, b: 2, a: 3]
Listの要素を<Atom, any>
のTupleにすると擬似的なkey-valueとして使える。ちなみにlist=[a: 1,b: 2,a: 3]
と宣言してもOK。
iex(48)> list[:a]
1
↑このようにすると先頭から:a
の要素を探しに行く。
Map
ElixirではMapは%{key => value}
という表現をする。
iex(49)> firstmap = %{1 => 1, :two => 2, "three" => "3"}
%{1 => 1, :two => 2, "three" => "3"}
keyとvalueはそれぞれどんな値でも良いが、Atomにしておくとmap.key
でアクセスできる。
iex(50)> firstmap.1
** (SyntaxError) iex:50: syntax error before: "1"
iex(50)> firstmap.two
2
iex(51)> firstmap.three
** (KeyError) key :three not found in: %{1 => 1, :two => 2, "three" => "3"}
分割代入みたいなこともできる。今更感はあるけどElixirにおいては分割代入などという言葉は使用せず「パターンマッチング」というらしい。
iex(51)> %{1 => first, "three" => third} = firstmap
%{1 => 1, :two => 2, "three" => "3"}
iex(52)> first
1
iex(53)> third
"3"
昔はkeyの数が大きくなると遅くなっていたらしいが今は何百万個もkeyをもつmapを作っても良いらしい。
参考文献
- はじめに - Elixir
- Elixir School 日本語訳 · Elixir School
- Elixirで試しに何か書いてみる(その1) - Qiita
- Kernel – Elixir v1.7.3
- Elixirで面食らった演算子・記法まとめ - Qiita
- Getting Started with Elixir | Pluralsight
- Elixir Tutorial
- Elixir: A Big-Picture Programming Language – freeCodeCamp.org
- The Best Tutorials To Learn Elixir For Beginners – Quick Code – Medium