摆脱 Julia 的“警告:为未更改的字符串重新定义常量”?
Posted
技术标签:
【中文标题】摆脱 Julia 的“警告:为未更改的字符串重新定义常量”?【英文标题】:Get rid of Julia's `WARNING: redifining constant` for strings that are not changed? 【发布时间】:2016-10-17 20:48:51 【问题描述】:在我的 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 行,这个空间可以用来显示以前提交的输出。
编辑(让自己更清楚):问题是即使我没有重新定义常量,也会显示此警告消息,这意味着我给它相同的值。而且,这个问题(据我所知)仅存在于 String
,不适用于 Int64
或 Float64
类型。例如:如果我写 const b = 1.2
然后 const b = 1.4
我将按预期收到警告消息。现在,如果我写const b = 1.2
然后const b = 1.2
(相同的值),我将不会收到警告,再次如预期。但是,这不适用于字符串常量。即使定义相同的值,您也会收到警告。
【问题讨论】:
整数和字符串之间的区别在于用于表示值的实际位。对于整数,相同的值始终具有相同的位。对于字符串,一个“hello”字符串可能具有与另一个“hello”字符串不同的位。当位保持不变时,没有警告(字符串的位实际上是指向内存中保存字符的位置的指针) 【参考方案1】:正如 L.Grozinger 在 cmets 中所指出的,只是对 Michael Ohlrogge 的回答的快速更新。从 Julia v1.6 开始,格式应该是(对于给定的 const x = 10
)
(@isdefined x) || (const x = 10)
【讨论】:
【参考方案2】:为了补充和详细说明 @aireties 的出色回答,Julia 目前有三个案例,当您在同一模块中执行 const x = a
并稍后再次执行 const x = b
时:
无警告:如果a === b
则a
和b
在Henry Baker 的EGAL [1, 2] 的意义上在程序上无法区分:替换@ 987654328@ 和b
不会影响任何程序的行为,因此对常量x
的重新定义是无操作的,不需要警告。
警告:如果a !== b
但typeof(a) == typeof(b)
那么在当前版本的 Julia 中,生成的代码仍然有效,因为它只取决于 x
的类型,它仍然存在不变,但程序的行为可能会受到对x
的更改的影响,因为旧值a
和新值b
在程序上是可区分的。
错误:如果typeof(a) != typeof(b)
重新分配x
将使之前使用x
生成的任何代码的假设无效。因此,不允许此分配。
===
谓词按类型和内容比较不可变值,因此 1.5
始终与 1.5
相同,因为无论您拥有多少此值的“实例”,它们都无法变异,因此无法区分以任何方式。另一方面,值1.5
(Float64) 和Float32(1.5)
是可区分的,因为它们具有不同的类型,即使它们表示完全相同的数值。然而,对于可变值,===
谓词按 identity 比较对象:除非它们是完全相同的对象,否则它们不会被视为 ===
。这是因为您可以通过更改其中一个并查看另一个是否更改来以编程方式区分两个可变值,即使它们以相等的值开始。
在 Julia 中,字符串仅按照约定是不可变的:String
类型包装了一个字节数组,它是可变的; String
类型只是不公开任何修改这些字节的函数。你仍然可以——大多数程序不建议这样做——进入并改变字符串的字节。这意味着相等字符串值的两个不同实例是不同的对象,因此彼此不是===
。因此,当您再次执行const x = "foo"
和稍后的const x = "foo"
时,您将两个不同的!==
字符串对象分配给x
,因此您会收到您要询问的警告:
julia> const x = "foo"
"foo"
julia> const x = "foo"
WARNING: redefining constant x
"foo"
另一方面,如果您将 same 字符串对象分配给 x
两次,则不会收到警告:
## in a new session ##
julia> foo = "foo"
"foo"
julia> const x = foo
"foo"
julia> const x = foo
"foo"
将来,我们可能会更改 String
的实现,使其实际上是不可变的,在这种情况下,使用相同类型的相同字符串值更新 const 绑定将不再产生警告,因为这两个值会互相===
。
【讨论】:
谢谢,这是一个很好的答案。但是我意识到我当时可能做错了什么(或误解了什么)!在我的代码中,我使用一些字符串作为“标识符”,例如:if pot_type == "constant"
做一些事情,elseif pot_type == "parabolic"
做一些其他事情。如果我没听错你说的话,有时这不是真的?到目前为止,在我的代码中我没有遇到任何问题......
啊,我想我确实误会了什么。您使用的是 ===
运算符而不是 ==
一个!
您可能需要考虑使用符号,因为:foo === :foo
但"foo" !== "foo"
。【参考方案3】:
如果您打算将某个东西用作常量,那么您真的不想多次定义它(毕竟,这就是常量的意义所在),当您多次运行脚本时,这正是您所需要的是做。此外,重新定义常量不会以任何方式影响您的代码并不完全正确——它实际上在某些情况下会严重损害性能。同样,这就是您使用常量的原因 - 通过明确表明计算机不需要担心特定对象的值发生变化来提高性能。
即使您为常量分配了相同的值,它仍然看起来像是对计算机的新分配。 IE。计算机不会,至少没有你更明确地告诉它(如下文所述)执行一些额外的逻辑来查看“哦,我想这与分配给它之前的常量的值相同,我想这可能没问题。”
一般来说,在开发过程中会出现多次运行相同脚本的情况,我猜这就是你正在做的事情。因此,作为对此的快速修复,您可以检查您的常量是否已定义,如果没有,则仅为其分配一个值。以下将实现这一点:
isdefined(:b) || (const b = 12)
作为一个长期解决方案,一旦您通过了开发阶段(在该阶段您不断地运行相同的代码以解决错误),那么您真的很想编写您的脚本,这样它就不会'不要多次定义一个常数,否则,正如我所提到的,在那种情况下它并不是一个真正的常数。
附:如果有帮助,上面代码sn-p的解释如下。 ||
运算符意味着 Julia 将评估第一个语句 isdefined(:b)
并且仅在第一个语句为 false 时继续执行第二个语句 (const b = 12)
。我们在第一条语句中使用 :
运算符来引用 b 的符号,即询问是否有任何分配给该符号 b
。
【讨论】:
非常感谢您的详细解答。我知道你所说的一切,是的,我当然处于这个发展阶段。我应该有你美妙的单行代码!愚蠢的我 :D 但你真的帮我摆脱了这个烦人的警告信息(顺便说一句,非字符串常量没有显示)。 操作。刮那个。其实你并没有帮助我!如果我使用您的代码,我将无法更改我想使用的潜力类型。我也意识到你不理解我的问题/帖子。此警告消息仅针对字符串变量显示。它不会显示为浮点数或整数,因为它应该是。如果我写const b = 1.2
,然后我写const b = 1.4
(重新定义),那么我将正确地收到警告消息,我应该这样做。但是,如果我写const b = 1.2
,然后再写const b = 1.2
(没有重新定义),我应该不会收到任何警告。问题出在字符串上。
@GeorgeDatseris 我想我不关注你。 isdefined(:b) || (const b = "12")
(即字符串分配)也可以正常工作。您是说您实际上想要定期重新定义常量(即更改您想要使用的潜力类型)但没有收到常量重新定义警告?还是您想要更多警告(例如浮动)? (顺便说一句,如果你使用const b = 12; b = 10
)
对不起,如果我不彻底:我在测试期间将常量String
-type 变量pot_type
从一个字符串值(例如"constant"
)更改为另一个(例如"parabolic"
) .如果我使用您的建议,那么在我希望具有不同潜力的连续运行之间,pot_type
将不会使用您的代码更改(因为它已经定义)。因此,这不是我的解决方案。
好吧,我想我的问题的答案很简单:我不应该将我的字符串变量定义为常量!抱歉打扰了,我才意识到!以上是关于摆脱 Julia 的“警告:为未更改的字符串重新定义常量”?的主要内容,如果未能解决你的问题,请参考以下文章