2015-02-07 98 views
80

檢查變量的類型在藥劑你如何檢查類型,如在Python:如何在藥劑

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

我在花好月圓閱讀有類型檢查,如「is_bitstring」,「is_float ','is_list','is_map'等,但如果您不知道類型可能是什麼?

回答

58

沒有直接的方法可以在Elixir/Erlang中獲得變量的類型。

您通常想知道變量的類型以便相應地執行;您可以使用is_*函數來根據變量的類型進行操作。

瞭解你Erlang有a nice chapter關於打入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 
+2

是否二郎/靈藥真的沒有存儲類型的信息?我是否真的需要爲現有的語言創建一個全新的包裝來使語言可用? O.o – Dmitry 2016-11-24 03:02:48

+0

@Dmitry你可用的意思是什麼?我能看到一個具體的例子,你可以使用類似'typeof(variable)'的結果嗎? – whatyouhide 2016-11-25 09:49:42

+0

當程序離開編譯時間並進入運行時時,關於某個對象的所有信息都將丟失。當我想要檢查正在運行的程序的信息時,知道發生了什麼的唯一方法就是檢查通過地圖網絡公開的事物。如果類型信息不可用,並且我想要檢查類型,則分析對象以獲取其類型的成本遠高於類型已經暴露的情況。 typeof允許我們分析正在運行的系統,並在運行時以允許類型檢查和多態性的方式對其進行擴展。 – Dmitry 2016-11-25 10:10:53

100

在靈藥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

如果要實現在花好月圓任何數據類型的功能,做到這一點的方法是定義該協議的協議和實現你想要的功能上工作的所有數據類型。不幸的是,你不能在守衛中使用協議功能。但是,一個簡單的「類型」協議可以非常直接地實現。

+6

這應該是被接受的答案。 – 2017-01-29 15:55:17

16

另一種方法是使用模式匹配。假設您使用Timex,它使用%DateTime{}結構,並且您想要查看某個元素是否爲一個。您可以在方法中使用模式匹配找到匹配項。

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

def is_a_datetime?(_) do 
    false 
end 
7

我會在這裏留下這個爲了有人希望搞清楚一個實際的理智版本。目前沒有很好的回答這個即將在谷歌...

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

如果你真的想要一個「類型」檢查器,你可以使用哲學家的石材工具中的工具輕鬆構建一個檢查器。 https://github.com/philosophers-stone。 Phenetic仍處於早期階段,但它可以做到這一點,還有更多。 – 2016-11-24 15:49:48

+0

輕鬆將自己綁定到外部依賴項?那將如何提高我與朋友分享代碼的能力?這是解決2個問題的途徑。 – Dmitry 2016-11-24 18:53:49

+0

感謝您編輯@aks;我現在可以回到4個空格了^ _^ – Dmitry 2016-12-15 00:30:51

6

我剛剛從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 
+0

巧妙地使用引用!我看到的Elixir代碼越多,它讓我想起Perl;那個〜w結構看起來和qw很相似//。我想知道Perl是否有一些巧妙的機制來模擬Lisplike引用。 – Dmitry 2016-11-26 18:15:01

+0

我不知道報價是如何工作的;可以使用正則表達式預處理器來模擬它,還是需要解析器遍歷整個代碼來執行宏擴展。 – Dmitry 2016-11-26 18:23:34

8

而且粘貼代碼進行調試,如果你在IEX是不是,你可以直接把它叫做:

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

我遇到了一個需要檢查參數需要確定類型的情況。也許可以採取更好的方式。

像這樣:

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

用法:

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

請忽略我,我發現更好的方法已經提供... – Bingoabs 2017-10-30 02:56:11