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


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow