首页 理论教育 Elixir函数式编程:无参数共享值

Elixir函数式编程:无参数共享值

时间:2026-01-27 理论教育 峰子 版权反馈
【摘要】:Elixir允许创建匿名函数,并将在外部定义的变量的值传给它。这是因为other_answer仅存在于make_answer函数范围内,而不存在于make_answer函数范围之外。请注意,我们给answer赋新值后,make_answer函数的结果未受到影响。白色框是IEx shell的作用域,而灰色框是匿名函数make_answer的作用域。因此,无论执行发生在何处,都会记住product_price的值。外部变量quantity被calculate函数中的quantity参数遮蔽了。这就是Elixir闭包的工作方式:可以在不使用参数的情况下与函数共享值。

使用闭包可以在函数间共享值。闭包可以访问代码块内部变量和外部变量的值。Elixir允许创建匿名函数,并将在外部定义的变量的值传给它。当无法控制函数的调用时,能够与函数共享值很有用,因为你无法将值传递给函数的参数,特别是当函数采用其他函数作为参数时。例如,我们可以使用Elixir的spawn来启动进程并异步执行函数。spawn将异步调用给定的函数,我们不能将参数传递给它。将参数值共享给该函数的一种方法是使用闭包:

函数say_hello记住了message变量的值,它使用Process.sleep在一秒钟后调用IO.puts,然后打印消息。出现在同一行上的打印和睡眠命令用分号分隔(命令是具名函数,稍后将详细介绍)。我们在不使用参数的情况下与say_hello共享了值。这是因为闭包记住了创建它们的词法作用域中引用的所有自由变量。

嘿,这里有副作用

本节使用了say_hello函数,它调用IO.puts,在控制台显示一条消息。由于控制台和我们的程序是不同的实体,当一个函数与外部进行交互时,它很容易受到外部的影响。所以我们说这个函数有副作用,它是非纯函数。我们将在第7章详细讨论纯函数和非纯函数。

作用域是程序的一部分,例如代码块。词法作用域与代码中定义变量的可见性有关。在函数定义中使用变量时,编译器将分析读取上层的代码,并将变量绑定到最接近的变量定义。在函数作用域之外定义的所有内容都属于上层作用域。如下面这个例子:

函数make_answer引用变量answer后,编译器将转到上层作用域寻找answer的定义。当我们尝试在函数范围之外调用other_answer时,将产生错误。这是因为other_answer仅存在于make_answer函数范围内,而不存在于make_answer函数范围之外。它就像一个单向镜:内部作用域可以看到外部的变量,反之则不行。

请注意,我们给answer赋新值后,make_answer函数的结果未受到影响。当我们定义函数引用函数作用域之外的变量时,变量绑定的当前值是不可变的。所以answer有新值后不会影响make_answer函数的结果。

图2-1说明了作用域的工作原理。白色框是IEx shell的作用域,而灰色框是匿名函数make_answer的作用域。

图2-1 两个作用域

可以看到,每个代码块都有自己的作用域。图2-2显示我们创建的每个代码块都有一个外部代码无法看到的空间。但是作用域内的代码可以看到外部定义的变量并引用它们。灰色阴影部分表示变量作用域不可见。图2-2也显示了每个作用域的变量可见性。

图2-2 两个作用域的变量可见性

外部作用域无法看到匿名函数内部定义的变量。匿名函数只能看到在自己的定义之前定义的变量。这就是匿名函数无法看到make_answer变量的原因:它是在函数创建表达式之后定义的。

理解了词法作用域,现在可以介绍自由变量和绑定变量了。在函数内部,当一个变量被定义为一个函数的参数或一个函数体中的局部变量时,它就是绑定的;否则,它是自由的。让我们测试一下闭包:

我们定义了quantity变量,但是函数calculate有一个同名参数。这意味着变量是绑定的,并且它的值不会被记住。product_price是自由的,但它不是calculate的参数,尽管函数体引用了它。因此,无论执行发生在何处,都会记住product_price的值。图2-3说明了作用域的划分。(https://www.xing528.com)

图2-3 作用域的划分

图2-4展示了变量在每个作用域中的可见性。

图2-4 变量在作用域中的可见性

现在可以清楚地看到,内部作用域中定义的quantity参数优先于外部作用域中定义的同名变量。外部变量quantity被calculate函数中的quantity参数遮蔽了。变量遮蔽不是一种好做法,因为它会使变量的值变得混乱和难以理解。应该避免这种情况!这就是Elixir闭包的工作方式:可以在不使用参数的情况下与函数共享值。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈