Julia 常量

                     

贡献者: 待更新

   本文授权转载自郝林的 《Julia 编程基础》。原文链接:第 3 章:变量与常量

3.4 常量

   在 Julia 中,常量是一种特殊的变量。我们可以使用关键字 const 来定义一个常量:

const A = 2020

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

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

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

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

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

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

julia>

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

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

   下面,我们来说 Julia 常量的最重要的 3 个特性。其中的一个比较反直觉的特性是:我们似乎可以改变一个常量的值。更明确地说,我们对常量的重新赋值只会引发一个警告,而不会得到一个错误。例如,我们看似可以对前面定义过的常量 A 进行重新赋值:

julia> A = 2050
WARNING: redefining constant A
2050

julia>

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

julia> const C = 2020 
2020

julia> f() = C + 30
f (generic function with 1 method)

julia> f()
2050

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

julia> C = 2030
WARNING: redefining constant C
2030

   然后,再次调用函数 f

julia> f()
2050

julia>

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

图
图 1:常量的重新定义

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

   因此,在 Julia 中,我们只能对常量进行重新定义,而不能进行重新赋值。正因为常量的重新定义所带来的效果有些反直觉,所以我们最好还是不要重新定义常量。为此,我们还应该让常量的名称看起来特别一些,比如全大写,以避免之后的误操作。我们还要注意程序输出中的此类警告,并及时纠正这种不好的做法。

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

julia> C = "2020"
ERROR: invalid redefinition of constant C
# 省略了一些回显的内容。

julia>

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

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

julia> const D = "2020"
"2020"

julia> D = "2020"
"2020"

julia> d = "2020"
"2020"

julia> D = d
"2020"

julia>

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

julia> const E = ["2020"]
1-element Array{String,1}:
 "2020"

julia> E = ["2020"]
WARNING: redefining constant E
1-element Array{String,1}:
 "2020"

julia>

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

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


致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 20 元,我们一周就能脱离亏损, 并在接下来的一年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。

                     

友情链接: 超理论坛 | ©小时科技 保留一切权利