LoginSignup
7
5

More than 5 years have passed since last update.

Elixir入門1

Posted at

Elixirとは

インストール

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では()parenthesesでしたがElixirでは{}bracesで括る。

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

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は[]bracketsで表します。

iex(37)> list = [1, :two, "three"]
[1, :two, "three"]

これも型はバラバラでOK。

配列arrayではなく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を作っても良いらしい。

参考文献

7
5
0

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
7
5