Elixir学習記
← 前 | 目次 | 次 → |
---|---|---|
1. 環境構築 | 2. データ型 | 3. 演算子 |
データ型
Integer
100 # 10進数
0b01100100 # 2進数(binary)
0o0144 # 8進数(octal)
0x0064 # 16進数(hexadecimal)
Float
1.0
1.0e+10 # 指数表記も可能
Atom
:atom
nil
Atom # 大文字から始めると Atom になる
Boolean
true # === :true
false # === :false
String
- UTF-8でエンコードされたバイト列
-
"(ダブルクォーテーション)
で囲む
"BitString"
# バイナリなので <> で結合する
"Bit" <> "String"
# 複数行
"""
Multi
Line
String
"""
# 式展開
var = "World"
"Hello #{var}" # == "Hello World"
"h" === <<104>>
"ł" === <<197, 130>>
Binaries
- バイト列(ByteString)のことだと解釈
-
,
区切りで各バイトを定義する - 1バイトは8ビットなので、0〜255の値を取ることができる
<< 104, 101, 108, 108, 111 >> # → (UTF-8 Encoding) → hello
BitString
- ビット列
- 長さが8の倍数になっているビット列=バイト列
<< 1 :: size(1) >>
List
- 要素の追加/削除が想定されるデータ向き
[1, :two, "three"]
CharList(文字リスト)
- 文字(コードポイント)のリスト
-
'(シングルクォーテーション)
で囲む -
String とは別物
- 基本はStringを使うが、古いライブラリの利用時等はこちらを使うこともあるらしい
'CharList'
# リストなので ++ で結合する
'Char' ++ 'List'
'h' === [104]
'ł' === [322]
Tuple
- 扱う要素が決まっているデータ向き
- 各要素へのアクセスや、要素数の取得はListより高速
{1, :two, "three"}
KeywordList
- List+Tuple+Atom
- 以下の特徴を持つ
- 順序がある
- 同じキーの要素を複数入れられる
- キーはAtomのみ
- 関数のoptionsなどで利用される
[a: 1, b: 2]
[{:a, 1}, {:b, 2}] # AtomをキーにしたTupleのList
Map
- ハッシュテーブル構造
- Keyword Listと対比すると以下特徴を持つ
- 順序がない
- 同じキーの要素は1つのみである
- パターンマッチングが行える
- Atom以外もキーに使える
%{a: 1, b: 2}
%{:a => 1, :b => 2, "c" => 3} # Atom以外もキーに指定可
Function(無名関数)
fn a, b -> a + b end
&(&1 + &2)
参考資料
感想
- 数値の大きさに応じて自動でスケールされるところなど、細かい部分が便利だと思った
- 「Binaries」という言葉がわかりづらかった
- 個人的には BitString こそ Binaries という言葉のイメージだった
- Listに要素を追加する際、先頭に加えなければ効率が落ちるというのは面倒に感じた
- インデックスで要素にアクセスする場合など、先頭に加えてしまうと他要素が全部ずれてしまう
- Elixir的にはあまりそういう処理をしないのかもしれない?
おまけ
Listの先頭追加と末尾追加にかかる時間を実際に計測してみた
# 計測用モジュールを定義
defmodule Test do
def concat2head(a, b) do
b ++ a
end
def concat2tail(a, b) do
a ++ b
end
end
# 引数分の長さのリストを返す無名関数
nl = &(1..&1 |> Enum.to_list())
1 ++ 100 vs 100 ++ 1
# :timer.tc/3 で処理時間を計測(単位はµs)
n = 100
:timer.tc(Test, :concat2head, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
:timer.tc(Test, :concat2tail, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
# result
23
22
1 ++ 10000 vs 10000 ++ 1
n = 10000
:timer.tc(Test, :concat2head, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
:timer.tc(Test, :concat2tail, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
# result
27
785
1 ++ 1000000 vs 1000000 ++ 1
n = 1000000
:timer.tc(Test, :concat2head, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
:timer.tc(Test, :concat2tail, [nl.(n), [1]])
|> elem(0)
|> IO.inspect
# result
28
16138
結論
- 末尾追加のほうだけ、要素数が増えるにつれ処理時間が増えている
- 要素数が少なければそれほど影響はない
- 要素数が大きくなる可能性がある場合、なるべく先頭から追加したほうが良さそう
- 要素の追加より取出のほうがはるかに時間がかかる(下記記事参考)
- 処理速度を意識するときは取出のほうを強く意識すべき