Elixir Language
Funktionen
Suche…
Anonyme Funktionen
In Elixir ist es üblich, anonyme Funktionen zu verwenden. Das Erstellen einer anonymen Funktion ist einfach:
iex(1)> my_func = fn x -> x * 2 end
#Function<6.52032458/1 in :erl_eval.expr/5>
Die allgemeine Syntax lautet:
fn args -> output end
Zur besseren Lesbarkeit können Sie die Argumente in Klammern setzen:
iex(2)> my_func = fn (x, y) -> x*y end
#Function<12.52032458/2 in :erl_eval.expr/5>
Um eine anonyme Funktion aufzurufen, rufen Sie sie mit dem zugewiesenen Namen auf und fügen Sie hinzu .
zwischen dem Namen und den Argumenten.
iex(3)>my_func.(7, 5)
35
Es ist möglich, anonyme Funktionen ohne Argumente zu deklarieren:
iex(4)> my_func2 = fn -> IO.puts "hello there" end
iex(5)> my_func2.()
hello there
:ok
Verwenden des Erfassungsoperators
Um anonyme Funktionen übersichtlicher zu gestalten, können Sie den Capture-Operator &
. Zum Beispiel anstelle von:
iex(5)> my_func = fn (x) -> x*x*x end
Du kannst schreiben:
iex(6)> my_func = &(&1*&1*&1)
Verwenden Sie bei mehreren Parametern die Nummer, die jedem Argument entspricht, von 1
:
iex(7)> my_func = fn (x, y) -> x + y end
iex(8)> my_func = &(&1 + &2) # &1 stands for x and &2 stands for y
iex(9)> my_func.(4, 5)
9
Mehrere Körper
Eine anonyme Funktion kann auch mehrere Körper enthalten (als Ergebnis eines Musterabgleichs ):
my_func = fn
param1 -> do_this
param2 -> do_that
end
Wenn Sie eine Funktion mit mehreren Körpern aufrufen, versucht Elixir, die von Ihnen angegebenen Parameter mit dem richtigen Körperteil der Funktion abzugleichen.
Schlüsselwortlisten als Funktionsparameter
Verwenden Sie Schlüsselwortlisten für 'options'-style Parameter, die mehrere Schlüssel-Wert-Paare enthalten:
def myfunc(arg1, opts \\ []) do
# Function body
end
Wir können die Funktion wie folgt aufrufen:
iex> myfunc "hello", pizza: true, soda: false
was äquivalent ist zu:
iex> myfunc("hello", [pizza: true, soda: false])
Die Argumentwerte sind als opts.pizza
bzw. opts.soda
verfügbar.
Alternativ können Sie Atome verwenden: opts[:pizza]
und opts[:soda]
.
Benannte Funktionen und private Funktionen
Benannte Funktionen
defmodule Math do
# one way
def add(a, b) do
a + b
end
# another way
def subtract(a, b), do: a - b
end
iex> Math.add(2, 3)
5
:ok
iex> Math.subtract(5, 2)
3
:ok
Private Funktionen
defmodule Math do
def sum(a, b) do
add(a, b)
end
# Private Function
defp add(a, b) do
a + b
end
end
iex> Math.add(2, 3)
** (UndefinedFunctionError) undefined function Math.add/2
Math.add(3, 4)
iex> Math.sum(2, 3)
5
Musterabgleich
Elixir ordnet einen Funktionsaufruf seinem Körper zu, basierend auf dem Wert seiner Argumente.
defmodule Math do def factorial(0): do: 1 def factorial(n): do: n * factorial(n - 1) end
Hier stimmt die Fakultät positiver Zahlen mit der zweiten Klausel überein, während factorial(0)
mit der ersten übereinstimmt. (Negative Zahlen werden der Einfachheit halber ignoriert). Elixir versucht die Funktionen von oben nach unten abzugleichen. Wenn die zweite Funktion über der ersten geschrieben wird, wird ein unerwartetes Ergebnis erwartet, da sie zu einer endlosen Rekursion führt. Weil factorial(0)
zu factorial(n)
passt
Leitsätze
Guard-Klauseln ermöglichen es uns, die Argumente vor der Ausführung der Funktion zu überprüfen. Guard-Klauseln werden aufgrund ihrer Lesbarkeit normalerweise if
und cond
vorgezogen, um dem Compiler eine bestimmte Optimierungstechnik zu erleichtern. Die erste Funktionsdefinition, bei der alle Wächter übereinstimmen, wird ausgeführt.
Hier ist eine Beispielimplementierung der Faktorialfunktion unter Verwendung von Guards und Pattern Matching.
defmodule Math do def factorial(0), do: 1 def factorial(n) when n > 0: do: n * factorial(n - 1) end
Das erste Muster stimmt überein, wenn (und nur wenn) das Argument 0
. Wenn das Argument nicht 0
, schlägt die Musterübereinstimmung fehl und die nächste Funktion wird geprüft.
Diese zweite Funktionsdefinition hat eine Schutzklausel: when n > 0
. Das bedeutet, dass diese Funktion nur übereinstimmt, wenn das Argument n
größer als 0
. Schließlich ist die mathematische Faktorfunktion für negative ganze Zahlen nicht definiert.
Wenn keine Funktionsdefinition (einschließlich ihrer Pattern Matching- und Guard-Klauseln) übereinstimmt, wird ein FunctionClauseError
ausgelöst. Dies geschieht für diese Funktion, wenn wir eine negative Zahl als Argument übergeben, da sie nicht für negative Zahlen definiert ist.
Beachten Sie, dass dieser FunctionClauseError
selbst kein Fehler ist. Die Rückgabe von -1
oder 0
oder eines anderen "Fehlerwerts", wie er in anderen Sprachen üblich ist, würde die Tatsache verdecken, dass Sie eine undefinierte Funktion aufgerufen haben, die die Fehlerquelle verbirgt und möglicherweise einen sehr schmerzhaften Fehler für zukünftige Entwickler verursacht.
Standardparameter
Sie können Standardparameter mit der folgenden Syntax an jede benannte Funktion übergeben: param \\ value
:
defmodule Example do def func(p1, p2 \\ 2) do IO.inspect [p1, p2] end end Example.func("a") # => ["a", 2] Example.func("b", 4) # => ["b", 4]
Capture-Funktionen
Verwenden Sie &
, um Funktionen von anderen Modulen zu erfassen. Sie können die erfassten Funktionen direkt als Funktionsparameter oder in anonymen Funktionen verwenden.
Enum.map(list, fn(x) -> String.capitalize(x) end)
Kann mit &
noch übersichtlicher gestaltet werden:
Enum.map(list, &String.capitalize(&1))
Um Funktionen erfassen zu können, ohne Argumente zu übergeben, müssen Sie deren Art explizit angeben, z. B. &String.capitalize/1
:
defmodule Bob do
def say(message, f \\ &String.capitalize/1) do
f.(message)
end
end