Julia变量复制机制与===运算符判定规则疑问解析
Julia变量绑定、
===判定与复制规则说明 以下是问题复现代码:
a = 1 b = 1 a === b # 独立定义的整数返回true a = 1 b = a a === b # true a = 10 # b的值仍然为1 a = (1,2) b = (1,2) a === b # 独立定义的元组返回true a = [1,2] b = [1,2] a !== b # 独立定义的数组返回true
核心前提
首先纠正一个普遍误解:Julia中的变量不是存储值的“盒子”,而是绑定到值上的名称标签;===的官方语义也不是“两个值内存地址完全相同”,而是“两个值在程序中不存在任何可观测的差异,是完全同一的实体”。内存地址重合只是===返回true的常见表现,不是判定标准。
问题1:独立定义的不可变值为什么===返回true?
整数、由不可变值构成的元组都属于不可变值,这类值一旦创建就无法修改内部内容。
- 对这类值,只要内容完全相等,你写任何代码都没法区分两个“内容相同的不可变值”是不是存放在不同内存位置——毕竟你改不了它,不存在“修改一个、观察另一个会不会变”的区分方法。
- 因此Julia编译器会自动对常用不可变值做驻留(Interning)、常量折叠优化:全局只保留一份值实例,所有绑定到这个值的变量都会指向同一份实例,哪怕你是分开独立赋值的,本质都是给同一个值贴了不同的名称标签,所以
===会返回true。 - 注意这个优化是编译器自主选择的实现细节,不是语言强制要求:比如数值极大的整数就算内容相等,也可能不做驻留,写代码时不要依赖这个特性,判断不可变值内容相等用
==即可。
问题2:b=a后===为true,给a重新赋值为什么b的值不变?
这里要严格区分变量重绑定和可变对象原地修改两个完全不同的操作:
- 执行
b = a时,只是把b这个名称标签,贴到了a当前指向的值上,此时两个标签指向同一个值,因此===返回true。 - 执行
a = 10时,做的操作是把a这个标签从原来的值1上撕下来,重新贴到新值10上,全程没有修改原来的值1(不可变值本身也不允许修改)。此时b的标签还贴在原来的1上,值自然不会发生变化。
对应可变对象的对比:如果a、b同时绑定到同一个数组
[1,2],执行a[1] = 100是在原地修改数组本身的内容,此时b指向的还是同一个数组,观测到的值会同步变化;但如果执行a = [100, 2],是给a重新绑定了一个全新的数组,b还是指向原数组,值不会变。
问题3:为什么独立定义的可变值(数组)===判定为不等?
数组、字典、可变结构体这类可变对象,创建后允许原地修改内部内容,这类对象是存在可观测差异的:
- 每执行一次
[1,2]字面量,Julia都会新分配一块独立的内存创建数组实例。哪怕两个数组初始内容完全一样,它们也是互相独立的实体——修改其中一个的内容,完全不会影响另一个,二者存在明确的可观测差异,因此===会返回false。 - 只有显式执行
b = a这类赋值操作时,两个变量才会绑定到同一个可变对象实例,此时修改其中一个的内容,另一个才能观测到变化。
内容的提问来源于stack exchange,提问作者TylerD
相关产品推荐
相关产品推荐

