- 0X1C 变量增删
- 这个示例中,演示了变量被函数污染(无意中修改)的情况。一开始我们创建变量x等于100,并且希望它作为常量,一直保持。
x=100 function fun(a) x=25 return a*x end fun(2) print(x)
- 函数中也用到了一个名叫x的变量。
- 当函数执行的时候修改变量x,其实就会修改一开始创建的那个变量。这并不是我最初希望的。(如果在函数中执行的是删除变量,可能就会不小心删除变量。)
- 这种问题实际上无法通过小心翼翼地命名彻底避开。因为大型的程序中有成千上万的变量是很正常的,凭人力去查找,修改变量名是不现实的。
- 为了限制函数运行时的影响范围,防止我们不小心修改一些不希望修改的变量。我们引入局部变量机制。为了区别,上例中的x,fun等不加任何特殊说明和修饰的变量,默认都称为“全局变量”。
- 在函数中,如果一个变量第一次出现时前边有关键字local做修饰。表明这是一个局部变量。局部变量也可以和赋值语句结合,如下所示:
local a local b=123
- 局部变量在函数运行时创建,运行结束后删除。它独立于同名的全局变量。同一个函数多次执行,各自的全局变量也相互独立。以下例子体现了这些特点。
a=123 function fun(x) local a=x print(a) end fun(33) print(a) fun(4) print(a)
- 直观上来说局部变量只对于从它定义开始到函数末尾结束这一段的代码是存在的。这一段代码就是这个局部变量的作用域。别的地方即使写了同样的变量名,也不能访问到这个局部变量,而回访问到同名的全局变量(或者别的局部变量)。
- 函数定义的参数列表中的形式参数,默认都是局部变量。例如:
x=100 function fun(x) x=8 end fun(123) print(x)
- 为了让程序可以模块化,方便调试。同时保证代码安全(不会因为一时疏忽,把重要的全局变量改掉)。我推荐函数中所有的变量都用局部变量。(形式参数都是局部变量,所以不再需要特殊说明。)
- 当函数中需要用到外部的数据时,都采用参数传递的方法。需要往外部传递时尽量都使用返回值。这样方便调试,且能保证代码安全。
- 关于参数传递的机制:
- 函数在执行的时候,首先会按照参数列表创建一组局部变量,用实参的值初始化这些形参。
- 然后执行函数中的代码。(执行函数体。)
- 当运行到return或者函数执行结束的时候返回返回值,继续调用函数的地方的运算。
- 演示:局部变量的使用 https://www.bilibili.com/video/av15851677/
- 从这里开始的几条,现在看不懂没有什么关系:理想状态下,函数运行过程中不应该修改任何非本地变量(最好也不要访问非本地变量,需要的数据都通过参数传递)。向外界传出数据也只通过返回值的方式。这称为无“副作用”。
- 把函数的返回值赋予变量从而改变函数外变量的值,这不是函数本身的副作用,而是赋值符号的作用。
- 无副作用的函数有很多优点。比如容易调试,仅仅需要检查输入是否正确,输出是否正确就能确定问题所在。又比如容易实现并发执行无干扰。因为对于一个确定的输入,它会有一个确定的输出,执行先后顺序不影响结果。
- 坚持使用无副作用的函数,将会导向函数式编程这种编程范式。
- 实际中的计算机几乎都是基于图灵机的构想,需要变量存储空间,命令顺序执行。这与函数式编程基于的Lambda演算等形式机器想去甚远,导致纯函数式在相当一段时间里都难以直接用于工程实际。但是我们有希望能有像函数式编程那样模块化的,互不影响的数据。因此而诞生了面向对象编程。
- 面向对象编程一定程度上允许函数副作用。但是把副作用限定在一个叫做“对象”的范围内。函数可以通过副作用修改的,只是他有访问权限的对象的属性。
- Lua是一门多范式编程语言。由于个人认为,副作用容易带来不可估量的麻烦。所以整体上本教程后续的介绍会偏向于无副作用。但是函数式和面向对象都会有所涉及。
- 0X1E 闭包