Elixir Language
funktioner
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