Sök…


Anonyma funktioner

I Elixir är det vanligt att använda anonyma funktioner. Att skapa en anonym funktion är enkelt:

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

Den allmänna syntaxen är:

fn args -> output end

För läsbarhet kan du placera parenteser kring argumenten:

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

För att åberopa en anonym funktion, ring den med det tilldelade namnet och lägg till . mellan namn och argument.

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

Det är möjligt att förklara anonyma funktioner utan argument:

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

Använda fångaroperatören

För att göra anonyma funktioner mer kortfattade kan du använda captureoperatören & . I stället för:

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

Du kan skriva:

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

Med flera parametrar, använd det nummer som motsvarar varje argument och räknar från 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

Flera kroppar

En anonym funktion kan också ha flera organ (som ett resultat av mönstermatchning ):

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

När du ringer en funktion med flera organ försöker Elixir matcha de parametrar du har tillhandahållit med rätt funktionskropp.

Sökordslistor som funktionsparametrar

Använd sökordslistor för "alternativ" -parametrar som innehåller flera nyckelvärdespar:

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

Vi kan kalla funktionen ovan så:

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

vilket motsvarar:

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

Argumentvärdena finns tillgängliga som opts.pizza respektive opts.soda .
Alternativt kan du använda atomer: opts[:pizza] och opts[:soda] .

Namngivna funktioner och privata funktioner

Namngivna funktioner

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

Privata funktioner

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

Mönstermatchning

Elixir matchar ett funktionsanrop till sin kropp baserat på värdet på sina argument.

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

Här matchar faktorn med positiva siffror den andra klausulen, medan factorial(0) matchar den första. (ignorerar negativa siffror för enkelhetens skull). Elixir försöker matcha funktionerna från topp till botten. Om den andra funktionen är skriven ovanför den första, kommer vi att få ett oväntat resultat eftersom det går till en oändlig rekursion. Eftersom factorial(0) matchar med factorial(n)

Vaktsklausuler

Vaktsklausuler gör det möjligt för oss att kontrollera argumenten innan vi utför funktionen. Skyddsklausuler föredras vanligen framför if och cond grund av deras läsbarhet och för att underlätta en viss optimeringsteknik för kompilatorn. Den första funktionsdefinitionen där alla vakter matchar exekveras.

Här är ett exempel på implementering av fabriksfunktionen med hjälp av vakter och mönstermatchning.

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

Det första mönstret matchar om (och bara om) argumentet är 0 . Om argumentet inte är 0 misslyckas mönstermatchningen och nästa funktion nedan kontrolleras.

Den andra funktionsdefinitionen har en skyddsklausul: when n > 0 . Detta betyder att den här funktionen bara matchar om argumentet n är större än 0 . När allt kommer omkring är den matematiska faktorafunktionen inte definierad för negativa heltal.

Om ingen av definitionerna (inklusive deras mönstermatchning och skyddsklausuler) matchar, kommer en FunctionClauseError att höjas. Detta händer för den här funktionen när vi skickar ett negativt tal som argument, eftersom det inte är definierat för negativa tal.

Observera att denna FunctionClauseError inte är ett misstag. Att återvända -1 eller 0 eller något annat "felvärde" som är vanligt på vissa andra språk skulle dölja det faktum att du kallade en odefinierad funktion, döljer källan till felet, eventuellt skapar ett enormt smärtsamt fel för en framtida utvecklare.

Standardparametrar

Du kan skicka standardparametrar till valfri funktion med syntax: 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]

Fånga funktioner

Använd & att fånga funktioner från andra moduler. Du kan använda de fångade funktionerna direkt som funktionsparametrar eller inom anonyma funktioner.

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

Kan göras mer kortfattad med hjälp av & :

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

Att fånga funktioner utan att skicka några argument kräver att du uttryckligen anger dess arity, t.ex. &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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow