4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Elixirのガード節を試してみる

Last updated at Posted at 2019-11-14

Elixirの関数には引数によって処理を分ける機能(Guard節)というのが存在する。
このガード節、結構いろいろな条件で処理を分岐できるのですが引数の型でも処理分けできるので今日はそれを試してみる

準備する

とりあえずライブラリ生成のお約束に則って

# Bundle gemみたいなコマンド
mix new hoge

# 生成されたディレクトリへ
cd hoge

# とりあえずテストを回しておこう
mix test

テストする

Elixirはテスト用のライブラリがしっかり入っているのでそれを持って先にテストを書いておく
とりあえず今回は引数を渡すと引数の型名を文字列で返してくれる関数を実装するということで
テストはこんな感じに

# test/hoge_test.exs
test 'Hoge.type関数は引数の型名を文字列で返す' do
  assert Hoge.type(:a) == "Atom"
  assert Hoge.type(nil) == "Nil"
  assert Hoge.type(1) == "Int"
  assert Hoge.type(1.1) == "Float"
  assert Hoge.type(true) == "Boolean"
  assert Hoge.type("s") == "String"
  assert Hoge.type([1,2,3]) == "List"
  assert Hoge.type(%{a: 1}) == "Map"
  assert Hoge.type({:A, 1}) == "Tupple"
  assert Hoge.type(fn -> IO.puts :a end) == "Function"
end

テストがかけたのでとりあえず Hogeモジュールに何もしない関数を書いてからテストを流すか

# lib/hoge.ex

def type(x) do

end

これでテストを流す
テストコマンドは mix test

mix test

  1) test 1 is number (HogeTest)
     test/hoge_test.exs:13
     Assertion with == failed
     code:  assert Hoge.type(1) == "Int"
     left:  nil
     right: "Int"
     stacktrace:
       test/hoge_test.exs:14: (test)

...

ちゃんと落ちることが確認できた

実装する

テストが失敗することがわかったので実装する


def type(x) when is_integer(x), do: "Int"
def type(x) when is_float(x), do: "Float"
def type(x) when is_bitstring(x), do: "String"
def type(x) when is_boolean(x), do: "Boolean" # NOTE: Booleanは内部的にはAtomなのでAtomより先に評価しないとAtom判定される
def type(x) when is_nil(x), do: "Nil" # NOTE: Nilは内部的にはAtomなのでAtomより先に評価しないとAtom判定される
def type(x) when is_atom(x), do: "Atom"
def type(x) when is_list(x), do: "List"
def type(x) when is_tuple(x), do: "Tupple"
def type(x) when is_map(x), do: "Map"
def type(x) when is_function(x), do: "Function"

気をつけないといけないのは BooleanNilAtomの関係
これ試して初めて気づいたけどどうもBooleanとNilはAtomで表現されているらしい :thinking:
なのでBooleanやNilよりもAtomのGuard節を上に書くと悲しいことに全部Atomとして結果が返ってくる

とりあえず実装はできたと思うのでテストを流す

mix test

Finished in 0.04 seconds
1 doctest, 1 tests, 0 failures

良さそう!

感想

引数ベースで処理を分けるのは他の言語だとバッドプラクティスという話を聞くけどElixirもといErlangがそういう言語仕様だからこうなるのは仕方ないね
せっかく言語にこういう書き方が実装されてるんだから積極的に使っていきたい所存
今回は条件分けに等値演算子などは使わなかったですが本当はそういうのを使ってもっといろいろな条件分岐していくこともできるそうな
いいなぁ...

4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?