使用=运算符在Julia中创建副本

使用=运算符在Julia中创建副本,julia,Julia,当我创建一些数组A并将其分配给B时 A = [1:10] B = A 我可以修改A,更改反映在B中 A[1] = 42 # B[1] is now 42 但是,如果我使用标量变量进行此操作,更改不会传播: a = 1 b = a a = 2 # b remains being 1 A = [1:10] B = A A = 0 # B remains being 1,2,...,10 我甚至可以将这些东西混合起来,将向量转换为标量,而变化不会传播: a = 1 b = a a = 2 #

当我创建一些数组A并将其分配给B时

A = [1:10]
B = A
我可以修改A,更改反映在B中

A[1] = 42
# B[1] is now 42
但是,如果我使用标量变量进行此操作,更改不会传播:

a = 1
b = a
a = 2
# b remains being 1
A = [1:10]
B = A
A = 0
# B remains being 1,2,...,10
我甚至可以将这些东西混合起来,将向量转换为标量,而变化不会传播:

a = 1
b = a
a = 2
# b remains being 1
A = [1:10]
B = A
A = 0
# B remains being 1,2,...,10

=
操作符具体做什么?当我想复制变量并修改旧变量以保持新变量的完整性时,我应该在什么时候使用
b=copy(a)
而不是
b=a

混淆源于此:赋值和变异不是一回事

赋值。赋值看起来像
x=…
=
左边是一个标识符,即变量名。赋值更改变量
x
引用的对象(这称为变量绑定)。它根本不会改变任何对象

突变。有两种典型的方法可以使朱莉娅的某些东西发生突变:
x.f=…
=
剩下的是字段访问表达式;
x[i]=…
=
的左边是一个索引表达式。目前,字段变异是最基本的——语法只能意味着通过改变字段来变异结构。这可能会改变。数组变异语法不是基本语法–
x[i]=y
表示
setindex!(x,y,i)
您可以向setindex添加方法!或者本地更改哪个通用函数
setindex。实际的数组分配是一个内置函数——一个用C实现的函数(我们知道如何生成相应的LLVM代码)

突变改变了对象的值;它不会更改任何变量绑定。执行上述任一操作后,变量
x
仍然引用它之前使用的相同对象;但是,该对象可能有不同的内容。特别是,如果该对象可以从其他范围访问(比如调用进行变异的函数),那么更改后的值将在那里可见。但是没有任何绑定发生更改–所有作用域中的所有绑定仍然引用相同的对象


你会注意到,在这个解释中,我从来没有提到过可变性或不变性。这是因为它与任何一个都无关——可变对象和不可变对象在赋值、参数传递等方面具有完全相同的语义。唯一的区别是,如果您尝试在x不可变时执行
x.f=…
,您将得到一个错误。

此行为类似于Java。A和B是变量,它们既可以保存“普通”数据类型,如整数、浮点等,也可以引用(即指针)到更复杂的数据结构。与Java不同,Julia将许多非抽象类型作为“普通”数据处理

您可以使用
isbits(A)
测试变量A是否包含位值,或者是否包含对另一个数据对象的引用。在第一种情况下,
B=A
将把
A
中的每一位复制到
B
的新内存分配中,否则,只复制对对象的引用


另外,还可以使用objref(A)

中的
指针\u,谢谢您的完整回答。正如我所理解的,我所有的
b=a
操作都是赋值,因此在所有情况下
b
都应该参考
a
。我遗漏了什么?当你做
A[1]=42时,那是变异,不是赋值。好吧,我不理解。但是当我做
b=a
时,它应该是赋值,因为它是
x=…
样式的操作,对吗?所以现在我把
b
指向
a
,并且
a
中的所有变化都应该反映在我评估b时,不是吗?是的,这是正确的,所有这些行为都完全符合这一点。如果执行
a=b
,则对
b
的任何更改也会影响
a
。如果绑定到
b
的值是一个像
42
一样的不可变值,那么你无论如何都不能对它进行变异,因此无法判断它是否被复制或引用。有一个问题,这个答案充其量是误导性的:可变性与不可变性是一种误导。可变值和不可变值在这两种语言中具有相同的语义–都具有引用语义。这是因为Julia和Java都没有可变的值类型,比如C的结构,它们的语义明显不同。基于您对问题所反映结果的预期,R语言可能不会让您感到惊讶。