2015-02-07 7 views
80

In Elixir, wie Sie für den Typen überprüfen wie in Python:Wie überprüfen Sie für die Art der Variable in Elixir

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

ich in Elixir lesen Sie dort Art Kontrolleure wie ‚is_bitstring‘ sind, ‚is_float ',' is_list ',' is_map 'usw., aber was ist, wenn Sie keine Ahnung haben, was der Typ sein könnte?

Antwort

58

Es gibt keinen direkten Weg, um den Typ einer Variablen in Elixir/Erlang zu erhalten.

Normalerweise möchten Sie den Typ einer Variablen kennen, um entsprechend zu agieren. Sie können die is_*-Funktionen verwenden, um basierend auf dem Typ einer Variablen zu agieren.

Lernen Sie einige Erlang hat a nice chapter über die Eingabe in Erlang (und damit in Elixir).

Der idiomatische Weg, um die is_* Familie von Funktionen wahrscheinlich sie in Mustern verwenden würde zu benutzen, übereinstimmt:

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

Hat Erlang/Elixir wirklich keine Typinformationen gespeichert haben? Muss ich wirklich einen ganz neuen Wrapper über existierende Typen erstellen, damit die Sprache verwendbar ist? O.o – Dmitry

+0

@Dmitry was meinst du mit verwendbar? Kann ich ein konkretes Beispiel sehen, in dem Sie das Ergebnis von "typeof (variable)" verwenden würden? – whatyouhide

+0

Wenn ein Programm die Kompilierzeit verlässt und die Laufzeit eingibt, sind alle Informationen darüber, was ein Objekt ist, verloren. Wenn ich Informationen eines laufenden Programms untersuchen möchte, kann ich nur durch die Inspektion von Dingen, die über ein Netzwerk von Karten verfügbar sind, wissen, was passiert. Wenn die Typinformationen nicht verfügbar sind und ich den Typ prüfen möchte, kostet es viel mehr, das Objekt zu analysieren, um seinen Typ zu erhalten, als wenn der Typ bereits verfügbar wäre. Mit typeof können wir das laufende System analysieren und zur Laufzeit so erweitern, dass Typchecking und Polymorphie möglich sind. – Dmitry

100

in Elixier Ab 1.2 gibt es einen i Befehl in iex, die den Typ Liste und mehr irgendeiner Elixir-Variable.

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 

Wenn Sie die i Befehl im Code suchen Sie werden sehen, dass dies über ein Protokoll implementiert wird.

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

Wenn Sie eine Funktion für jeden Datentyp in Elixir, die Art und Weise zu implementieren, das zu tun ist, ein Protokoll und Implementierung des Protokolls für alle Datentypen, die Sie die Funktion definieren mögen, die Arbeit an . Leider können Sie in Wächtern keine Protokollfunktion verwenden. Ein einfaches "Typ" -Protokoll wäre jedoch sehr einfach zu implementieren.

+6

Dies sollte die akzeptierte Antwort sein. –

16

Ein anderer Ansatz besteht darin, Mustervergleiche zu verwenden. Angenommen, Sie verwenden Timex, das eine Struktur %DateTime{} verwendet, und Sie möchten sehen, ob ein Element eins ist. Sie können eine Übereinstimmung mithilfe des Mustervergleichs in der Methode finden.

7

Ich lasse das hier nur für jemanden, hoffentlich herauszufinden, eine eigentlich gesunde Version. Im Moment gibt es keine guten Antworten auf diese auf Google kommen ...

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 

Aus Gründen der Vollständigkeit, Testfälle:

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 

Hier ist eine Lösung mit Protokollen; Ich bin mir nicht sicher, ob sie schneller sind (ich hoffe, dass sie keine Schleife über alle Typen machen), aber sie ist ziemlich hässlich (und zerbrechlich; wenn sie einen grundlegenden Typ hinzufügen oder entfernen oder umbenennen, wird es ihn brechen).

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

Wenn Sie wirklich einen "Typ" Checker wollen, können Sie leicht einen mit den Tools in der Philosopher's Stone Org bauen. https://github.com/philosophers-stein. Die Phetik ist noch in den frühen Tagen, aber es kann dies und noch viel mehr. –

+0

binden mich leicht an eine externe Abhängigkeit? Wie wird das meine Fähigkeit verbessern, Code mit Freunden zu teilen? Dies ist ein Weg zu 2 Problemen. – Dmitry

+0

Danke für die Bearbeitung @aks; Ich kann jetzt tatsächlich zurück zu 4 Räumen gehen^_^ – Dmitry

6

ich fügen Sie einfach den Code aus 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

Cleverer Gebrauch des Zitats! Je mehr ich Elixir code sehe, desto mehr erinnert es mich an Perl; Das ~ w-Konstrukt sieht qw // sehr ähnlich. Ich frage mich, ob Perl einen raffinierten Mechanismus hat, Lisplike-Zitat zu simulieren. – Dmitry

+0

Ich frage mich, wie Zitat funktioniert; kann es mit einem Präprozessor für reguläre Ausdrücke emuliert werden oder erfordert es einen Parser, der den gesamten Code durchläuft, um eine Makroerweiterung durchzuführen. – Dmitry

8

Auch Zwecke für die Fehlersuche, wenn Sie nicht in iex sind, können Sie es direkt anrufen:

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

Ich bin auf eine Situation gestoßen, die notwendig ist, um zu überprüfen, ob der Parameter ein bestimmter Typ sein muss. Vielleicht kann man einen besseren Weg gehen.

So:

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

Verbrauch:

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

Bitte ignorieren Sie mich, ich finde mehr bessere Methode bereits zur Verfügung gestellt ... – Bingoabs

Verwandte Themen