首页
模块和函数

使用defmodule宏定义模块,使用def宏定义函数

iex> defmodule Math do
...>   def sum(a, b) do
...>     a + b
...>   end
...> end

iex> Math.sum(1, 2)
3

编译

如果math.ex文件有以下代码:

defmodule Math do
  def sum(a, b) do
    a + b
  end
end

可以使用elixirc来进行编译:

$ elixirc math.ex

执行后,会在该文件所在的目录生成一个Elixir.Math.beam字节码文件

再次打开iex,即可执行里面的函数

iex> Math.sum(1, 2)
3

iex中使用c 文件名可以直接调用模块里的函数

iex> c "math.ex"
[Math]

iex> Math.sum(1, 2)
3

elixir 项目通常包括三个目录:

  • ebin - 包含编译好的字节码文件

  • lib - 包含 elixir 代码 (通常是 .ex 文件)

  • test - 包含测试代码 (通常是 .exs 文件)

脚本模式

exs文件用于脚本模式,它不会生成.beam文件。但两种文件在执行时都可以将其模块编译并加载到内存中

defmodule Math do
  def sum(a, b) do
    a + b
  end
end

IO.puts Math.sum(1, 2)

这样执行它:

$ elixir math.exs

命名函数

在模块中,使用def/2定义函数,使用defp/2定义私有函数。

函数声明支持哨兵子句和多个子句,这个特性可以替代其他语言的 if else

defmodule Math do
  def zero?(0) do
    true
  end

  def zero?(x) when is_integer(x) do
    false
  end
end

?是一种命名规范,返回布尔值的函数以?结尾,参照文档

if宏类型,命名函数也支持do:do/end这两种模式

可以在一行中使用do:,在多行中使用do/end

默认参数

参数设置默认值可以用 argument \\ value 语法:

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 Math do
  def zero?(0), do: true
  def zero?(x) when is_integer(x), do: false
end

对于上面的函数,可以使用&Math.zero?/1分配给变量fun,调用方式跟匿名函数一样,使用fun.(0)调用

iex> Math.zero?(0)
true
iex> fun = &Math.zero?/1
&Math.zero?/1
iex> is_function(fun)
true
iex> fun.(0)
true

捕获语法可以作为创建函数的快捷方式:

iex> fun = &(&1 + 1)
#Function<6.71889879/1 in :erl_eval.expr/5>
iex> fun.(1)
2

iex> fun2 = &"Good #{&1}"
#Function<6.127694169/1 in :erl_eval.expr/5>
iex)> fun2.("morning")
"Good morning"

&1表示传递给函数的第一个参数,上面的&(&1 + 1)等同于fn x -> x + 1

从模块捕获一个函数,可以使用&Module.function()

iex> fun = &List.flatten(&1, &2)
&List.flatten/2
iex> fun.([1, [[2], 3]], [4, 5])
[1, 2, 3, 4, 5]

&List.flatten(&1, &2)等同于fn (list, tail) -> List.flatten(list, tail)

匿名函数

匿名函数可以内联创建并由关键字fnend分隔:

iex> add = fn a, b -> a + b end
iex> add.(1, 2)
3
iex> is_function(add)
true
iex> is_function(add, 2) # 检查是否是带两个参数的函数
true
iex> is_function(add, 1)
false

管道操作符

管道操作符 |> 把前一个表达式的结果作为第一个参数传递给后一个表达式

foo(bar(baz(new_function(other_function()))))

# 等价于

other_function() |> new_function() |> baz() |> bar() |> foo()

最佳实践:如果函数的参数大于 1,一定要使用括号,便于理解

# 检查尾部字符串
iex> "elixir" |> String.ends_with?("ixir")
true