# 函數

## 匿名 (Anonymous) 函數

``````iex> sum = fn (a, b) -> a + b end
iex> sum.(2, 3)
5
``````

### & 簡寫符號

``````iex> sum = &(&1 + &2)
iex> sum.(2, 3)
5
``````

## 模式比對

Elixir 使用模式比對來檢查所有可能的比對選項，並選擇第一個吻合的選項來執行：

``````iex> handle_result = fn
...>   {:ok, result} -> IO.puts "Handling result..."
...>   {:ok, _} -> IO.puts "This would be never run as previous will be matched beforehand."
...>   {:error} -> IO.puts "An error has occurred!"
...> end

iex> some_result = 1
1
iex> handle_result.({:ok, some_result})
Handling result...
:ok
iex> handle_result.({:error})
An error has occurred!
``````

## 命名 (Named) 函數

``````defmodule Greeter do
def hello(name) do
"Hello, " <> name
end
end

iex> Greeter.hello("Sean")
"Hello, Sean"
``````

``````defmodule Greeter do
def hello(name), do: "Hello, " <> name
end
``````

``````defmodule Length do
def of([]), do: 0
def of([_ | tail]), do: 1 + of(tail)
end

iex> Length.of []
0
iex> Length.of [1, 2, 3]
3
``````

### 函數命名和引數數目 (Arity)

``````defmodule Greeter2 do
def hello(), do: "Hello, anonymous person!"   # hello/0
def hello(name), do: "Hello, " <> name        # hello/1
def hello(name1, name2), do: "Hello, #{name1} and #{name2}"
# hello/2
end

iex> Greeter2.hello()
"Hello, anonymous person!"
iex> Greeter2.hello("Fred")
"Hello, Fred"
iex> Greeter2.hello("Fred", "Jane")
"Hello, Fred and Jane"
``````

### 函數和模式比對

``````defmodule Greeter1 do
def hello(%{name: person_name}) do
IO.puts "Hello, " <> person_name
end
end
``````

``````iex> fred = %{
...> name: "Fred",
...> age: "95",
...> favorite_color: "Taupe"
...> }
``````

``````# call with entire map
...> Greeter1.hello(fred)
"Hello, Fred"
``````

``````# call without the key we need returns an error
...> Greeter1.hello(%{age: "95", favorite_color: "Taupe"})
** (FunctionClauseError) no function clause matching in Greeter3.hello/1

The following arguments were given to Greeter3.hello/1:

# 1
%{age: "95", favorite_color: "Taupe"}

iex:12: Greeter3.hello/1

``````

``````# incoming map
iex> fred = %{
...> name: "Fred",
...> age: "95",
...> favorite_color: "Taupe"
...> }
``````

`Greeter1.hello/1` 期待這樣的參數：

``````%{name: person_name}
``````

`Greeter1.hello/1` 中，傳入的映射 (`fred`) 是根據參數 (`%{name: person_name}`) 賦值：

``````%{name: person_name} = %{name: "Fred", age: "95", favorite_color: "Taupe"}
``````

``````defmodule Greeter2 do
def hello(%{name: person_name} = person) do
IO.puts "Hello, " <> person_name
IO.inspect person
end
end
``````

``````person = %{name: "Fred", age: "95", favorite_color: "Taupe"}
``````

``````%{name: person_name} = %{name: "Fred", age: "95", favorite_color: "Taupe"}
``````

1. `person` ，指向 `%{name: "Fred", age: "95", favorite_color: "Taupe"}`
2. `person_name` ，指向 `"Fred"`

``````# call with entire person
...> Greeter2.hello(fred)
"Hello, Fred"
%{age: "95", favorite_color: "Taupe", name: "Fred"}
# call with only the name key
...> Greeter4.hello(%{name: "Fred"})
"Hello, Fred"
%{name: "Fred"}
# call without the name key
...> Greeter4.hello(%{age: "95", favorite_color: "Taupe"})
** (FunctionClauseError) no function clause matching in Greeter2.hello/1

The following arguments were given to Greeter2.hello/1:

# 1
%{age: "95", favorite_color: "Taupe"}

iex:15: Greeter2.hello/1
``````

``````defmodule Greeter3 do
def hello(person = %{name: person_name}) do
IO.puts "Hello, " <> person_name
IO.inspect person
end
end
``````

``````# call with same old Fred
...> Greeter3.hello(fred)
"Hello, Fred"
%{age: "95", favorite_color: "Taupe", name: "Fred"}
``````

### 私有 (Private) 函數

``````defmodule Greeter do
def hello(name), do: phrase() <> name
defp phrase, do: "Hello, "
end

iex> Greeter.hello("Sean")
"Hello, Sean"

iex> Greeter.phrase
** (UndefinedFunctionError) function Greeter.phrase/0 is undefined or private
Greeter.phrase()
``````

### 監視 (Guards)

``````defmodule Greeter do
def hello(names) when is_list(names) do
names
|> Enum.join(", ")
|> hello
end

def hello(name) when is_binary(name) do
phrase() <> name
end

defp phrase, do: "Hello, "
end

iex> Greeter.hello ["Sean", "Steve"]
"Hello, Sean, Steve"
``````

### 預設 (Default) 引數值

``````defmodule Greeter do
def hello(name, language_code \\ "en") do
phrase(language_code) <> name
end

defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end

iex> Greeter.hello("Sean", "en")
"Hello, Sean"

iex> Greeter.hello("Sean")
"Hello, Sean"

iex> Greeter.hello("Sean", "es")
"Hola, Sean"
``````

``````defmodule Greeter do
def hello(names, language_code \\ "en") when is_list(names) do
names
|> Enum.join(", ")
|> hello(language_code)
end

def hello(name, language_code \\ "en") when is_binary(name) do
phrase(language_code) <> name
end

defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end

** (CompileError) iex:31: definitions with multiple clauses and default values require a header.

def foo(:first_clause, b \\ :default) do ... end
def foo(:second_clause, b) do ... end

one should write:

def foo(a, b \\ :default)
def foo(:first_clause, b) do ... end
def foo(:second_clause, b) do ... end

def hello/2 has multiple clauses and defines defaults in one or more clauses
iex:31: (module)
``````

``````defmodule Greeter do
def hello(names, language_code \\ "en")
def hello(names, language_code) when is_list(names) do
names
|> Enum.join(", ")
|> hello(language_code)
end

def hello(name, language_code) when is_binary(name) do
phrase(language_code) <> name
end

defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end

iex> Greeter.hello ["Sean", "Steve"]
"Hello, Sean, Steve"

iex> Greeter.hello ["Sean", "Steve"], "es"
"Hola, Sean, Steve"
``````
Caught a mistake or want to contribute to the lesson? Edit this page on GitHub!