web-dev-qa-db-ja.com

Elixirで変数のタイプをどのように確認しますか

Elixirでは、Pythonなどでどのように型をチェックしますか:

>>> a = "test"
>>> type(a)
<type 'str'>
>>> b =10
>>> type(b)
<type 'int'>

私はElixirで「is_bitstring」、「is_float」、「is_list」、「is_map」などの型チェッカーがありますが、型が何であるかわからない場合はどうすればよいですか?

124
Low Kian Seong

Elixir/Erlangで変数の型を取得する直接的な方法はありません。

通常は、それに応じて動作するために変数のタイプを知りたいです。変数の型に基づいて動作するために、is_*関数を使用できます。

Learn You Some Erlangには ニースの章 Erlang(したがってElixir)での入力についての説明があります。

関数のis_*ファミリを使用する最も慣用的な方法は、おそらくパターンマッチで使用することです。

def my_fun(arg) when is_map(arg), do: ...
def my_fun(arg) when is_list(arg), do: ...
def my_fun(arg) when is_integer(arg), do: ...
# ...and so on
89
whatyouhide

Elixir 1.2以降、iexにはiコマンドがあり、Elixir変数のタイプなどをリストします。

iex> foo = "a string" 
iex> i foo 
Term
 "a string"
Data type
 BitString
Byte size
 8
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
  <<97, 32, 115, 116, 114, 105, 110, 103>>
Reference modules
  String, :binary

iコマンドのコードを見ると、これがプロトコルを介して実装されていることがわかります。

https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex

Elixirの任意のデータ型の関数を実装する場合、その方法は、関数を機能させたいすべてのデータ型のプロトコルとプロトコルの実装を定義することです。残念ながら、ガードではプロトコル機能を使用できません。ただし、単純な「タイプ」プロトコルを実装するのは非常に簡単です。

また、デバッグ目的で、iexを使用していない場合は、直接呼び出すことができます。

IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]
25
atomkirk

別のアプローチは、パターンマッチングを使用することです。 %DateTime{}構造体を使用するTimexを使用しており、要素が1つかどうかを確認するとします。メソッドでパターンマッチングを使用して一致を見つけることができます。

def is_a_datetime?(%DateTime{}) do
  true
end

def is_a_datetime?(_) do
  false
end
23
popedotninja

誰かが実際に健全なバージョンを見つけ出せるように、ここに置いておきます。現時点では、グーグルでこれについて良い答えはありません...

defmodule Util do
    def typeof(self) do
        cond do
            is_float(self)    -> "float"
            is_number(self)   -> "number"
            is_atom(self)     -> "atom"
            is_boolean(self)  -> "boolean"
            is_binary(self)   -> "binary"
            is_function(self) -> "function"
            is_list(self)     -> "list"
            is_Tuple(self)    -> "Tuple"
            _                 -> "idunno"
        end    
    end
end

完全を期すために、テストケースは次のとおりです。

cases = [
    1.337, 
    1337, 
    :'1337', 
    true, 
    <<1, 3, 3, 7>>, 
    (fn(x) -> x end), 
    {1, 3, 3, 7}
]

Enum.each cases, fn(case) -> 
    IO.puts (inspect case) <> " is a " <> (Util.typeof case)
end

プロトコルを使用したソリューションを次に示します。それらがより高速かどうかはわかりませんが(すべてのタイプでループを実行していないことを期待しています)、それはかなりいです(そして壊れやすいです。基本的なタイプを追加または削除したり、名前を変更すると、それが壊れます)。

defprotocol Typeable, do: def typeof(self)
defimpl Typeable, for: Atom, do: def typeof(_), do: "Atom"
defimpl Typeable, for: BitString, do: def typeof(_), do: "BitString"
defimpl Typeable, for: Float, do: def typeof(_), do: "Float"
defimpl Typeable, for: Function, do: def typeof(_), do: "Function"
defimpl Typeable, for: Integer, do: def typeof(_), do: "Integer"
defimpl Typeable, for: List, do: def typeof(_), do: "List"
defimpl Typeable, for: Map, do: def typeof(_), do: "Map"
defimpl Typeable, for: PID, do: def typeof(_), do: "PID"
defimpl Typeable, for: Port, do: def typeof(_), do: "Port"
defimpl Typeable, for: Reference, do: def typeof(_), do: "Reference"
defimpl Typeable, for: Tuple, do: def typeof(_), do: "Tuple"

IO.puts Typeable.typeof "Hi"
IO.puts Typeable.typeof :ok
13
Dmitry

https://elixirforum.com/t/just-created-a-typeof-module/2583/5 :)からコードを貼り付けるだけです

defmodule Util do
  types = ~w[function nil integer binary bitstring list map float atom Tuple pid port reference]
  for type <- types do
    def typeof(x) when unquote(:"is_#{type}")(x), do: unquote(type)
  end
end
11
user3197999

誰も言及していないから

IO.inspect/1

オブジェクトをコンソールに出力... JSON.stringifyとほぼ同等

テスト中にオブジェクトがどのように見えるかを一生理解できない場合に非常に役立ちます。

2
John Nicholas

特定のタイプである必要があるパラメーターを確認する必要がある状況に遭遇しました。たぶん、より良い方法で活動できるでしょう。

このような:

@required [{"body", "binary"},{"fee", "integer"}, ...]
defp match_desire?({value, type}) do
  apply(Kernel, :"is_#{type}", [value])
end

使用法:

Enum.map(@required, &(match_desire?/1))
0
Bingoabs