Elixir-匿名函数

Elixir是函数式语言,所以函数式它的一种基本类型。

一般语法

匿名函数用 fn 创建

fn
    parameter-list -> body
    parameter-list -> body ...
end

一个参数列表(圆括号可省略),一个函数体,二者通过 -> 隔开。

1
iex> sum = fn (a, b) -> a + b end

调用的时候

1
2
iex> sum.(1, 2)
3

函数模式匹配

回忆一下,Elixir 没有赋值概念,是将值和模式进行匹配。

1
2
3
4
iex> swap = fn {a, b} -> {b, a} end
...
iex> swap.({1, 2})
{2, 1}

一个函数,多个函数体

例如打开文件的时候,对结果进行多个匹配。

1
2
3
4
iex> handle_open = fn
...>{:ok, file} -> "Read data: #{IO.read(file, :line)}"
...>{_, error} -> "Error: #{:file.format_error(error)}"
...>end

_ 当参数可以省略的时候,用 _ 去充当一个占位。

1
2
3
4
iex> handle_open.(File.open("code/hello.exs"))
"Read data: IO.puts \"Hello,world!\"\n"
iex> handle_open.(File.open("nonexistent"))
"Error: no such file or directory"

可见当文件存在,第一个参数会匹配:ok,走第一行函数体。
文件不存在时候,匹配第二行函数体,输出错误。

函数中的函数

1
2
3
4
iex> fun1 = fn -> fn -> "Hello" end end
...
iex> fun1.().()
"Hello"

闭包

刚才那段代码,改造一下:

1
2
3
4
iex> fun1 = fn name -> fn -> "Hello,#{name}" end end
...
iex> fun1.("jack").()
"Hello,jack"

可见,内部函数调用了外部函数的变量。

变量 name 被绑定到外部函数的作用域里,当定义内部函数的时候,它继承这个作用域并将 name 的绑定值传递到里面。

这就是闭包(closure):作用域将其中的变量绑定封闭起来,并将它们打包到稍后能被保存且使用的东西上。

函数做为参数进行传递

1
2
3
4
5
6
iex> fun1 = fn name -> fn -> "Hello,#{name}" end end
...
iex> fun2 = fn (fun, name) -> fun.(name) end
...
iex> fun2.(fun1, "jack")
"Hello,jack"

另一个例子

1
2
iex> Enum.map [1, 2], fn elem -> elem * 2 end
[2, 4]

& 运算符

创建简短辅助的函数很普遍,所以Elixir提供一个快捷的创建函数的方式。上面的例子,改造下:

1
2
iex> Enum.map [1, 2], &(&1 * 2) end
[2, 4]

看官赏点饭钱可好~