@ChrisRackauckas 的答案就其本身而言是准确的——即对于可变对象。然而,这个问题的含义远不止于此,所以我将在这里详细说明一下。
The ===
运算符(的别名is
函数)实现 Henry Baker 的 EGAL 谓词 [1 http://home.pipeline.com/~hbaker1/ObjectIdentity.html, 2 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.23.9999]: x === y
当两个对象在编程上无法区分时,即为真 - 即,您无法编写代码来证明两者之间的任何差异x
and y
。这归结为以下规则:
- 对于可变值(数组、可变复合类型),
===
检查对象身份:x === y
为真,如果x
and y
是同一个对象,存储在内存中的同一位置。
- 对于不可变的复合类型,
x === y
为真,如果x
and y
具有相同的类型 - 因此具有相同的结构 - 并且它们相应的组件都是递归的===
.
- 对于位类型(不可变的数据块,例如
Int
or Float64
), x === y
为真,如果x
and y
包含完全相同的位。
这些规则,递归地应用,定义了行为===
.
The ==
另一方面,函数是用户可定义的,并实现“抽象值相等”。过载能力是一个关键区别:
- The
===
不可重载——它是一个具有固定、预定义行为的内置函数。您无法扩展或更改其行为。
- The
==
可重载——它是一个带有中缀语法的普通(对于 Julia)泛型函数。它具有后备定义,可以为用户定义的类型提供有用的默认行为,但您可以通过添加新的、更具体的方法来更改您认为合适的设置==
适合您的类型。
提供有关如何进行的更多详细信息==
对于内置类型的行为以及当人们扩展它时它对于用户定义类型的行为应该如何,从the docs http://docs.julialang.org/en/release-0.4/stdlib/math/?#Base.==:
例如,所有数字类型都按数值进行比较,忽略
类型。字符串作为字符序列进行比较,忽略
编码。
您可以将其视为“直观平等”。如果两个数在数值上相等,则它们是==
:
julia> 1 == 1.0 == 1 + 0im == 1.0 + 0.0im == 1//1
true
julia> 0.5 == 1/2 == 1//2
true
但请注意,==
实现精确的数值相等:
julia> 2/3 == 2//3
false
这些值不相等,因为2/3
是浮点值0.6666666666666666
,这是最接近的Float64
到数学值 2/3 (或用 Julia 表示法表示有理值,2//3
), but 0.6666666666666666
不完全等于 2/3。而且,==
遵循浮点数的 IEEE 754 语义。
这包括一些可能意想不到的属性:
- 有明显的正浮点零和负浮点零(
0.0
and -0.0
): 他们是==
,尽管它们的行为不同,因此不是===
.
- 有许多不同的非数字(
NaN
)值:它们不是==
对自己、对彼此或任何其他价值;他们每个人===
对他们自己,但不是!==
彼此之间,因为它们有不同的位。
例子:
julia> 0.0 === -0.0
false
julia> 0.0 == -0.0
true
julia> 1/0.0
Inf
julia> 1/-0.0
-Inf
julia> NaN === NaN
true
julia> NaN === -NaN
false
julia> -NaN === -NaN
true
julia> NaN == NaN
false
julia> NaN == -NaN
false
julia> NaN == 1.0
false
这有点令人困惑,但这就是 IEEE 标准。
此外,文档==
还指出:
集合一般应实现==
通过致电==
递归地处理所有内容。
因此,价值平等的概念由下式给出==
递归地扩展到集合:
julia> [1, 2, 3] == [1, 2, 3]
true
julia> [1, 2, 3] == [1.0, 2.0, 3.0]
true
julia> [1, 2, 3] == Any[1//1, 2.0, 3 + 0im]
true
因此,这继承了标量的缺点==
比较:
julia> a = [1, NaN, 3]
3-element Array{Float64,1}:
1.0
NaN
3.0
julia> a == a
false
The ===
另一方面,比较总是测试对象同一性,因此即使两个数组具有相同的类型并包含相同的值,只有当它们是相同的数组时它们才相等:
julia> b = copy(a)
3-element Array{Float64,1}:
1.0
NaN
3.0
julia> a === a
true
julia> a === b
false
julia> b === b
true
原因是a
and b
不是===
是即使他们现在这里碰巧包含相同的数据,因为它们是可变的而不是同一个对象,您可以改变其中之一,然后很明显它们是不同的:
julia> a[1] = -1
-1
julia> a # different than before
3-element Array{Int64,1}:
-1
2
3
julia> b # still the same as before
3-element Array{Int64,1}:
1
2
3
因此你可以说a
and b
通过突变是不同的对象。相同的逻辑不适用于不可变对象:如果它们包含相同的数据,那么只要它们具有相同的值,它们就无法区分。因此,不可变值不再受特定位置的束缚,这是编译器能够如此有效地优化不可变值的使用的原因之一。
也可以看看:
- 摆脱 Julia 的“警告:为未更改的字符串重新定义常量”? https://stackoverflow.com/questions/37857436/get-rid-of-julias-warning-redifining-constant-for-strings-that-are-not-chang/37862270#37862270