Skip to main content

作用域

6.7 作用域

作用域(也被称为冲突域)是一个非常重要的概念,它在编程语言中起到了关键的作用。一般来说,作用域是一个区域,它规定了在该区域内定义的变量、函数、和对象的可见性和生命周期。换句话说,作用域定义了在哪里和在何时可以访问一个变量或者一个实体。

为了更好地理解作用域的概念,以下是一个代码示例:

globalVar = "I'm global"; // 全局作用域
{    localVar := "I'm local"; // 局部作用域
    println(globalVar); // 输出 "I'm global"    println(localVar); // 输出 "I'm local"}
println(globalVar); // 输出 "I'm global"println(localVar); // 报错,localVar 在此作用域内未定义

在以上代码中,globalVar 是在全局作用域中定义的,所以它可以在代码的任何地方被访问。而 localVar 是在{}包裹的代码块的作用域内定义的,所以它只能在代码块内部被访问。当试图在代码块外部访问 localVar 时,程序会报错,因为 localVar 在外部的作用域内未定义。

这个例子展示了作用域如何控制变量的可见性和生命周期。在作用域之后,局部变量 localVar 就会被销毁,因为它的生命周期限制在了代码块作用域内。此外,由于 localVar 只在代码块作用域内可见,所以它不会影响到函数外部的任何代码,这就避免了可能的名称冲突。

在编程时,理解和正确使用作用域是至关重要的,因为它能够帮助编程者编写出结构清晰、易于维护的代码。通过有效地利用作用域,编程者可以控制变量、函数和对象的可见性和生命周期,从而提高代码的可读性和可维护性。

6.7.1 作用域**的嵌套关系**#

Yak中很多语句都会创建自身的作用域,一般来说可以认为每一对{}内包裹的代码块都是一个新的作用域,同时Yak中的作用域使用嵌套关系组织,如果某个标识符在当前作用域找不到,则会在父作用域中查找。

以下的代码示例简单讲述了作用域的嵌套以及从父作用域中获取变量,两个函数都创建了自己的新作用域,并且使用了无法找到的标识符,则在父作用域查找,得到对应的值。

a = 1f = () => {    println("a:", a)    b = 2    f2 = () => {        println("b:", b)    }    f2()}f()

代码运行结果如下:

a: 1b: 2

因为Yak所有标识符都是变量,因此除了父作用域标识符的使用,在嵌套的作用域内,还可以进行父作用域标识符数据的修改。

a = 1println("a = ", a){    a = 2    println("in block a = ", a)}println("after block a = ", a)

比如以上的代码示例,其中在 block 内是一个新的作用域,使用变量 a 的时候将会直接修改外部的 a 变量。此段代码运行结果如下:

a =  1in block a =  2after block a =  2

6.7.2 强制创建**局部变量**#

Yak的标识符可向上查找和修改的特定使得闭包函数等操作实现较为简单,但是在一些情况下,我们希望内部变量和外部变量进行区分,也就是避免名称冲突的问题。

Yak提供:=赋值语句,表示在当前作用域强制创建一个全新的标识符,并忽略上层作用域是否存在同名的标识符。

在下面的代码示例中可以清晰的了解到强制赋值的特性。

a = 1println("a = ", a){    a := 2 // 这里使用强制赋值    println("in block a = ", a)}println("after block a = ", a)

和之前修改父作用域变量的代码一致,区别只是将原本的赋值修改为了强制赋值。则{}内部的 a 和外部的 a 并不是同一个变量,对内部 a 标识符的任何操作也不会修改外部的 a。

运行结果如下:

a =  1in block a =  2after block a =  1