LoginSignup
9
1

More than 1 year has passed since last update.

Elixir 学習記(2. データ型)

Last updated at Posted at 2023-02-13

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

結論

  • 末尾追加のほうだけ、要素数が増えるにつれ処理時間が増えている
  • 要素数が少なければそれほど影響はない
  • 要素数が大きくなる可能性がある場合、なるべく先頭から追加したほうが良さそう
  • 要素の追加より取出のほうがはるかに時間がかかる(下記記事参考)
    • 処理速度を意識するときは取出のほうを強く意識すべき

9
1
20

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1