Szukaj…


Funkcje anonimowe

W Elixir powszechną praktyką jest używanie anonimowych funkcji. Tworzenie anonimowej funkcji jest proste:

iex(1)> my_func = fn x -> x * 2 end
#Function<6.52032458/1 in :erl_eval.expr/5>

Ogólna składnia to:

fn args -> output end

Aby zapewnić czytelność, możesz umieścić nawiasy wokół argumentów:

iex(2)> my_func = fn (x, y) -> x*y end
#Function<12.52032458/2 in :erl_eval.expr/5>

Aby wywołać funkcję anonimową, wywołaj ją według przypisanej nazwy i dodaj . między nazwą a argumentami.

iex(3)>my_func.(7, 5)
35

Możliwe jest deklarowanie funkcji anonimowych bez argumentów:

iex(4)> my_func2 = fn -> IO.puts "hello there" end
iex(5)> my_func2.()
hello there
:ok

Korzystanie z operatora przechwytywania

Aby bardziej zwięzłe funkcje anonimowe można było użyć operatora przechwytywania & . Na przykład zamiast:

iex(5)> my_func = fn (x) -> x*x*x end

Możesz pisać:

iex(6)> my_func = &(&1*&1*&1)

W przypadku wielu parametrów użyj liczby odpowiadającej każdemu argumentowi, licząc od 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

Wiele ciał

Funkcja anonimowa może również mieć wiele obiektów (w wyniku dopasowania wzorca ):

my_func = fn
  param1 -> do_this
  param2 -> do_that
end

Kiedy wywołujesz funkcję z wieloma ciałami, Elixir próbuje dopasować parametry, które podałeś z odpowiednim ciałem funkcji.

Listy słów kluczowych jako parametry funkcji

Użyj list słów kluczowych dla parametrów w stylu „opcji”, które zawierają wiele par klucz-wartość:

def myfunc(arg1, opts \\ []) do
  # Function body
end

Możemy wywołać powyższą funkcję w następujący sposób:

iex> myfunc "hello", pizza: true, soda: false

co jest równoważne z:

iex> myfunc("hello", [pizza: true, soda: false])

Wartości argumentów są dostępne odpowiednio jako opts.pizza i opts.soda .
Alternatywnie możesz użyć atomów: opts[:pizza] i opts[:soda] .

Funkcje nazwane i funkcje prywatne

Nazwane funkcje

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

Funkcje prywatne

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

Dopasowywanie wzorów

Eliksir dopasowuje wywołanie funkcji do swojego ciała na podstawie wartości jego argumentów.

defmodule Math do
    def factorial(0): do: 1
    def factorial(n): do: n * factorial(n - 1)
end

Tutaj silnia liczb dodatnich odpowiada drugiej klauzuli, podczas gdy factorial(0) odpowiada pierwszej. (ignorując liczby ujemne dla uproszczenia). Elixir próbuje dopasować funkcje od góry do dołu. Jeśli druga funkcja zostanie zapisana powyżej pierwszej, uzyskamy nieoczekiwany wynik, gdy dojdzie do niekończącej się rekurencji. Ponieważ factorial(0) pasuje do factorial(n)

Klauzule ochronne

Klauzule ochronne pozwalają nam sprawdzić argumenty przed wykonaniem funkcji. Klauzule straży są zwykle korzystne if i cond ze względu na czytelność i zrobić pewną technikę optymalizacji łatwiej kompilator. Pierwsza definicja funkcji, w której wszystkie strażniki są wykonywane.

Oto przykładowa implementacja funkcji silniowej z wykorzystaniem osłon i dopasowywania wzorców.

defmodule Math do
    def factorial(0), do: 1
    def factorial(n) when n > 0: do: n * factorial(n - 1)
end

Pierwszy wzorzec pasuje, jeśli (i tylko wtedy) argumentem jest 0 . Jeśli argument nie jest równy 0 , dopasowanie wzorca kończy się niepowodzeniem i sprawdzana jest następna funkcja poniżej.

Ta druga definicja funkcji ma klauzulę ochronną: when n > 0 . Oznacza to, że ta funkcja pasuje tylko wtedy, gdy argument n jest większy niż 0 . W końcu matematyczna funkcja czynnikowa nie jest zdefiniowana dla ujemnych liczb całkowitych.

Jeśli żadna definicja funkcji (w tym ich dopasowanie do wzorca i klauzule ochronne) nie jest zgodna, wywoływany jest błąd FunctionClauseError . Dzieje się tak w przypadku tej funkcji, gdy jako argument przekazujemy liczbę ujemną, ponieważ nie jest ona zdefiniowana dla liczb ujemnych.

Zauważ, że sam FunctionClauseError nie jest błędem. Zwrócenie -1 lub 0 lub innej „wartości błędu”, jak to często bywa w niektórych innych językach, ukryłoby fakt, że wywołałeś niezdefiniowaną funkcję, ukrywając źródło błędu, prawdopodobnie tworząc ogromny bolesny błąd dla przyszłego programisty.

Parametry domyślne

Możesz przekazać parametry domyślne do dowolnej nazwanej funkcji, używając składni: 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]

Funkcje przechwytywania

Użyj & do przechwytywania funkcji z innych modułów. Możesz użyć przechwyconych funkcji bezpośrednio jako parametrów funkcji lub w ramach funkcji anonimowych.

Enum.map(list, fn(x) -> String.capitalize(x) end)

Może być bardziej zwięzły przy użyciu & :

Enum.map(list, &String.capitalize(&1))

Przechwytywanie funkcji bez przekazywania żadnych argumentów wymaga jawnego określenia jego arity, np. &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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow