谈到全局变量、局部变量和静态变量,就涉及到两个概念:作用域和生存期。

这是两个完全不同的概念,虽然很多时候相互关联。作用域是作用在空间上的,比如一个变量在代码的哪些行能访问,哪些行不能访问。而生存期是作用在时间上的,比如一个变量的值在函数返回后是否失效。

全局变量

全局变量比较好理解,如果一个变量是全局变量,那么程序中的所有代码都可以访问到这个变量(除非存在同名的局部变量或者静态变量)。全局变量用 global 定义。

看一个例子。

a := 1
global b := 2
c := 3

fun()

fun()
{
    ; a 不是全局变量,访问不了,弹出空字符串
    MsgBox, % a

    ; b 是全局变量,弹出 2
    MsgBox, % b

    ; 在函数里也可以将 c 变成全局变量
    global c
    ; 弹出 3
    MsgBox, % c
}

注意代码里的 a 并不是全局变量,虽然它的作用域要比函数里的局部变量要大,在所有文件的函数外都可以访问,但在函数内它是不能被访问到的,这算是一个特例。

局部变量

在函数里使用的变量通常是局部变量。

fun()
; a 并不是全局变量,弹出空字符串
MsgBox, % a
; b 是全局变量,弹出 2
MsgBox, % b

fun()
{
    a := 1
    global b := 2
}

注意这里 b 是在函数里定义的全局变量,但不管是在什么地方定义的,在其他地方都可以访问到。

静态变量

全局变量和局部变量的作用域和生存期都不一样。全局变量的作用域和生存期都是全局的,局部变量的作用域是在函数内部,生存期是从函数开始执行到函数返回。

但还有一种比较特别的变量是静态变量。

; 弹出 1 1
fun()
; 弹出 1 2
fun()

fun()
{
    a := 1
    static b := 1
    MsgBox, % a " " b
    a++
    b++
}

a 就是普通的局部变量,因为每次执行 a 都会被初始化为 1,所以两次运行 fun 函数时 a 的值都是 1。但 b 是一个静态变量(使用 static 定义)。静态变量的作用域和局部变量一样,只能在函数内访问。但生存期和全局变量一样,也就是说一个静态变量定义后,它的值会一直有效,即使函数已经返回了。所有第二次运行 fun 函数后,b 的值已经是 2 了。

使用场景

那么什么分别在什么情况下使用三者呢?

没有特殊需求的场景,都应该使用局部变量,这也是默认的情况。

如果一个变量是需要全局有效的,那么使用全局变量。但全局变量会导致代码的耦合度比较高,不方便维护,所以尽量少用。有些看似需要使用全局变量的场景,其实使用函数的参数传递更合理。

如果某个局部变量需要只初始化一次(一般情况是因为初始化有开销,这是主要的场景),或者需要保留上次运行的结果(这会导致代码容易滋生 bug,并且难于测试,尽量少用),那么需要将这个局部变量修改成静态变量。

除了全局变量、局部变量、静态变量,还有在类中的变量,这个我会在类中单独讲。