摆脱 Julia 的“警告:为未更改的字符串重新定义常量”?

Get rid of Julia's `WARNING: redifining constant` for strings that are not changed?

在我的 julia 代码中,我使用了一些常量。其中一些常量是字符串(它们用作标识符)。我的问题是,每当我 运行 一个 julia 脚本时,我总是会收到以下针对常量字符串的警告, 即使我没有更改常量 WARNING: redefining constant pot_type

为了说明我的问题,这里有一个 MWE:

const pot_type = "constant"
const b = 12
println("Given parameters: Potential = $pot_type, b = $b .")

如果我运行这个脚本两次,我会得到上述警告。 不仅如此,如果我在 Julia 控制台中输入 const something = "somestring" 两次,同样的事情也会发生。我刚得到 WARNING: redefining constant something

我知道这不会以任何方式影响我的代码,但是是否可以删除或修复此警告?在我的实际代码中,每次我提交内容时它都会创建 5 行,这个 space 可用于显示以前提交的输出。

编辑(让自己更清楚):问题是即使我没有重新定义常量,也会显示此警告消息,这意味着我给它相同的值。而且,这个问题(据我所知)仅存在于 String ,而不存在于 Int64Float64 类型。例如:如果我写 const b = 1.2 然后 const b = 1.4 我会按预期收到警告消息。现在,如果我写 const b = 1.2,然后写 const b = 1.2(相同的值),我将不会再次收到警告,正如预期的那样。但是,这不适用于字符串常量。即使定义相同的值,您也会收到警告。

如果您打算将某个东西用作常量,那么您真的不想多次定义它(毕竟,这就是常量的意义所在)并且当您 运行 您的脚本多次次,这正是你在做什么。此外,重新定义常量不会以任何方式影响您的代码这一说法并不完全正确——在某些情况下,它实际上会对性能造成相当大的影响。同样,这就是您使用常量的原因 - 通过明确表示计算机不需要担心特定对象的值发生更改来提高性能。

即使您为常量分配相同的值,它仍然看起来像是对计算机的新分配。 IE。计算机不会,至少没有你更明确地告诉它(正如我在下面描述的那样)执行一些额外的逻辑来查看 "oh, I guess this is just the same value that is getting assigned to the constant that it had before, I suppose that's probably ok."

一般来说,您 运行多次使用同一个脚本的情况只会在开发过程中出现,我猜这就是您正在做的事情。因此,作为对此的快速修复,您可以检查您的常量是否已经定义,如果没有,则只为其分配一个值。以下将实现这一点:

isdefined(:b) || (const b = 12)

作为一个长期的解决方案,一旦你过了开发阶段(在这个阶段你保持 运行 一次又一次地使用相同的代码来解决错误)那么你真的很想编写你的脚本,这样它就不会多次定义一个常量,否则,正如我提到的,在那种情况下它并不是一个真正的常量。

P.S。如果有帮助,上面代码片段的解释如下。 || 运算符意味着 Julia 将计算第一个语句 isdefined(:b) 并且仅继续第二个语句,如果第一个语句为假,则 (const b = 12) 。我们在第一条语句中使用 : 运算符来引用 b 的符号,即询问是否有任何分配给该符号的东西,b.

为了补充和阐述@aireties 的出色回答,目前在 Julia 中有三种情况,当您执行 const x = a 然后在同一模块中再次执行 const x = b 时:

  1. 无警告: if a === b then a and b 在 Henry Baker 的意义上在编程上无法区分EGAL [1, 2]:用 b 替换 a 不会影响任何程序的行为,因此常量 x 的重新定义是空操作,不需要警告.

  2. 警告: if a !== b but typeof(a) == typeof(b) then in the current version of Julia, generated code remains valid because it only取决于 x 的类型,它保持不变,但程序的行为可能会受到更改为 x 的影响,因为旧值 a 和新值 b 在编程上是可区分的。

  3. 错误: 如果 typeof(a) != typeof(b) 重新分配 x 将使任何先前使用 [=19= 生成的代码的假设无效].因此这个赋值是不允许的。

=== 谓词按类型和内容比较不可变值,因此 1.5 始终与 1.5 相同,因为无论您有多少 "instances" 这个值,它们不能突变,因此不能以任何方式区分。另一方面,值 1.5 (Float64) 和 Float32(1.5) 是可区分的,因为它们具有不同的类型,即使它们表示完全相同的数值。但是,对于可变值,=== 谓词通过 身份 比较对象:除非它们是完全相同的对象,否则它们不会被视为 ===。这是因为您可以通过更改其中一个并查看另一个是否更改来以编程方式区分两个可变值,即使它们以相等的值开始也是如此。

在 Julia 中,字符串只是按照惯例是不可变的:String 类型包装了一个字节数组,它是可变的; String 类型只是不公开任何修改这些字节的函数。您仍然可以——在大多数程序中不建议这样做——进入并改变字符串的字节。这意味着相等字符串值的两个不同实例是不同的对象,因此彼此不是 ===。因此,当您再次执行 const x = "foo" 和稍后的 const x = "foo" 时,您将两个不同的 !== 字符串对象分配给 x 因此您会收到您询问的警告:

julia> const x = "foo"
"foo"

julia> const x = "foo"
WARNING: redefining constant x
"foo"

另一方面,如果您将 相同的 字符串对象分配给 x 两次,则不会收到警告:

## in a new session ##

julia> foo = "foo"
"foo"

julia> const x = foo
"foo"

julia> const x = foo
"foo"

将来,我们可能会更改 String 的实现,使其实际上是不可变的,在这种情况下,使用相同类型的相等字符串值更新 const 绑定将不再产生警告,因为这两个值彼此 ===

如评论中 L.Grozinger 所述,只需快速更新 Michael Ohlrogge 的回答即可。从 Julia v1.6 开始,格式应该是(对于给定的 const x = 10

(@isdefined x) || (const x = 10)