当需要同时定义多个常量时,我们还可以使用平行赋值法:

    1. const W, U, V = 2020, 2030, 2050

    在这里,常量WUV的值分别为202020302050

    我们已经知道,为全局变量附加类型标注目前是行不通的。实际上,Julia 官方现在不建议我们在程序中使用全局变量。因为全局变量总是会给程序带来不小的性能负担。这正是用于全局变量的值及其类型都是可以被随时改变的。而全局常量可以让这个问题迎刃而解。所以,我们应该使用全局常量,而不是全局变量。这也是 Julia 中很重要的一条编码建议。

    相反,在局部,我们应该使用局部变量,而不是局部常量。因为定义一个局部常量完全是没有必要的。Julia 一旦在局部碰到一个不变的变量就会把它优化成常量。你其实用不着专门去记这条编码建议。因为定义局部常量根本就不符合 Julia 的语法规则,例如:

    1. julia> function get_uint32(x)
    2. const y::UInt32 = x
    3. y
    4. end
    5. ERROR: syntax: unsupported `const` declaration on local variable around REPL[1]:2
    6. # 省略了一些回显的内容。
    7. julia>

    不过,这个语法规则的制定原因我们还是应该了解的。

    另外,与其他的一些编程语言不同,Julia 中的常量的值不仅可以是数值和字符串,还可以是像数组这样的可变对象。也正因为如此,Julia 常量只能保证名称与值之间的绑定是不可变的,但是并不能防止值本身的变化,比如数组中的某个元素值的改变。所以,我们尽量不要把本身可变的值赋给全局常量。

    根据警告的内容可知,Julia 称其为对常量的重新定义。这相当于放弃了以前的常量定义,而采用了新的定义。那么,常量的重新定义与我们之前说的重新赋值到底有什么不一样呢?我们可以通过下面的示例进行理解。

    1. julia> const C = 2020
    2. 2020
    3. julia> f()
    4. 2050

    我先定义了一个名称为C、值为2020的常量,紧接着又用一种简洁的方式定义了一个名称为f的函数。这个函数的功能很简单,即:在常量C代表的值之上再加30并将结果返回。现在,我们重新定义常量C

    1. julia> C = 2030
    2. WARNING: redefining constant C
    3. 2030

    然后,再次调用函数f

    可以看到,调用f函数后得到的结果依然为2050。这是因为函数f使用的仍然是在它之前定义的那个常量C,而不是我们重新定义的常量C

    图 3-2 常量的重新定义

    我们可以想象,如果真有一种方法可以对常量C进行重新赋值的话,那么再次调用f函数肯定不会得到这样的结果。

    Julia 常量的第二个重要特性是,如果我们在重新定义常量的时候试图赋予它一个不同类型的值,那么就会得到一个错误。例如:

    1. ERROR: invalid redefinition of constant C
    2. # 省略了一些回显的内容。
    3. julia>

    注意,这里报出的错误是“对常量C的重新定义无效”,而不是“不能改变常量C的类型”。所以,这里的规则是,在对常量进行重新定义时只能赋予一个与前值类型相同的值。

    基于此,常量的第三个重要特性就比较好理解了。这个特性就是,如果在重新定义常量时赋予它相同的值,那么既不会引发警告也不会导致错误报告。比如:

    1. "2020"
    2. julia> D = "2020"
    3. "2020"
    4. julia> d = "2020"
    5. "2020"
    6. julia> D = d
    7. "2020"
    8. julia>

    不过,需要注意,这只是针对不可变对象(或者说本身不可变的值)而言的。对于可变对象(比如数组),即使前后两个值看起来相同,Julia 也照样会发出警告。例如:

    所以,还是那句话,我们尽量不要把本身可变的值赋给常量。顺便说一下,上述代码中的字面量["2020"]表示的是只包含了一个元素值(即)的一维数组。倘若一个一维数组中有多个元素值,那么我们就需要用英文逗号把这些元素值分隔开,如["2020", "2050"]

    由以上特性可知,常量看似可以被当做类型固定的全局变量来使用。但实际上,对常量的重新定义会埋下隐患,而且由此引发的程序错误将会很难排查和定位。所以,我们可以使用常量来存储全局性的对象,但最好不要对它进行重新定义。另外,我们尽量不要把可变对象赋给常量。