Nao000のぶろぐ

蝶を追っている少年になりたい

【elixir】caseですでに使用している変数にパターンマッチさせる場合はピン演算子「^」を使う

悩んだときのcase

ピン演算子未使用のときのサンプルです。"nothing"が出力される期待をしていました。

    defmodule Casesample do

        def main do
            a = 3
            b = 1

            case b do
                a -> "pattern match a"
                _ -> "nothing"
            end
        end
    end

結果は"pattern match a"が出力されます。

    /home/trial # iex casesample.ex
    Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]

    warning: variable "a" is unused (if the variable is not meant to be used, prefix it with an underscore)
      casesample.ex:8: Casesample.main/0

    warning: variable "a" is unused (if the variable is not meant to be used, prefix it with an underscore)
      casesample.ex:4: Casesample.main/0

    Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> Casesample.main
    "pattern match a"
    iex(2)>

最初に変数aがunusedと表示されている時点でわかりますが、意図した結果になりません。変数bの値を変数aに束縛させるのでcase内の変数aは変数bの値になります。以下のようにそのまま変数aを返すと結果がわかります。

    defmodule Casesample do

        def main do
            a = 3
            b = 1

            case b do
                a -> a
                _ -> "nothing"
            end
        end
    end
    iex(2)> r Casesample
    warning: redefining module Casesample (current version defined in memory)
      casesample.ex:1

    warning: variable "a" is unused (if the variable is not meant to be used, prefix it with an underscore)
      casesample.ex:4: Casesample.main/0

    {:reloaded, Casesample, [Casesample]}
    iex(3)> Casesample.main
    1
    iex(4)>

結果のとおり変数bの値である1が出力されます。

解決するには

ピン演算子を使います。

    defmodule Casesample do

        def main do
            a = 3
            b = 1

            case b do
                ^a -> "pattern match a"
                _ -> "nothing"
            end
        end
    end

結果は期待通り"nothing"が出力されます。

    iex(5)> r Casesample
    warning: redefining module Casesample (current version defined in memory)
      casesample.ex:1

    warning: this check/guard will always yield the same result
      casesample.ex:8

    {:reloaded, Casesample, [Casesample]}
    iex(6)> Casesample.main
    "nothing"
    iex(7)>

終わり

書籍「プログラミングElixir」の12章にあるcase節には特にこれについて記載はなさそうでした。elixir-langには記載されていました。

参考資料