我对朱莉娅来说相当新,所以对我可能有的语言的任何误解表示道歉。我最近大部分时间都在使用Python,并且大量使用了SymPy及其代码生成功能,看起来Julia的元编程功能是为了完全按我喜欢的方式编写代码而构建的。
特别是,我想在一组较小的构建块中构建Julia中的块矩阵,其间有一些不同的操作。出于调试目的,并且因为在其他计算中使用了各种中间矩阵,我想将它们保存为包含变量的表达式,这样我就可以快速循环并测试不同的不同输入,而无需将所有内容包装在函数中。
现在,对于一个最小的案例研究,我说有两个表达式mat1 = :a
和mat2 = :b
,我想要组合起来形成一个新的第三个表达式:
mat3 = :($mat1 + $mat2)
上述方法正常直到我修改mat1
和mat2
,在这种情况下,我必须重新评估mat3
才能反映此更新。我认为,这是因为$mat1 + $mat2
没有通过引用传递mat1
和mat2
,而是在评估该行时插入内部的表达式。我想要实现的行为是mat1
和mat2
在我调用eval(mat3)
之前不会插入,最好是最小的样板。
是否有可能以方便的语法实现这一目标?
答案 0 :(得分:9)
mat3
将反映mat1
和mat2
的变异,但不会反映mat1
的{em>重新绑定和{ {1}}。了解突变和重新绑定之间的区别非常重要。
修改对象的数据时发生突变。请注意,这不会影响任何名称,只会影响对象。这可以通过多种方式表现出来,包括mat2
等函数和具有复杂左侧的赋值语法,如push!
。
例如,以下所有都是变异的例子:
A[1] = 5
名称A未更改; A仍然指向同一个对象。 A = [1, 2, 3]
A[1] = 4
表示的对象已被修改。
A
名称A未更改; A仍然指向同一个对象。 A = :(f(x))
A.args[1] = :g
表示的对象已被修改。
A
名称mat1 = :(f(x))
mat2 = :(f(y))
mat3 = :($mat1 + $mat2)
mat1.args[1] = :g
未更改;它仍然指向同一个对象。该对象已被修改。 mat1
也引用了同一个对象,并且因为它已被修改,它将反映这些更改。实际上,现在mat3
包含mat3
。
(也称为作业)
当没有修改对象数据但是名称的目标更改为其他对象的目标时,会发生重新绑定。这由一个简单的:(g(x) + f(y))
赋值表示,左侧是反弹的东西。
=
此处x = 2
x = 3
正在从对象x
反弹到对象2
。我们不是更改对象3
。实际上,因为2
是不可变的对象,所以不允许改变对象2
。相反,2
的可观察值发生变化的原因是因为它现在引用了另一个对象:x
。
3
再一次,我们不是改变向量A = [1, 2, 3]
A = [4, 2, 3]
;我们正在创建一个新的向量,现在A
引用了这个新向量。区分突变和重新绑定很重要。同样,变异作用于对象,重新绑定作用于名称。
A
请注意,简单赋值不会 mutate mat1 = :x
mat2 = :y
mat3 = :($mat1 + $mat2)
mat1 = :z
引用的对象:x
;它只是将mat1
重新绑定到不同的对象mat1
。这意味着包含对象:z
的{{1}}不会受到影响。
请注意,mat3
是不可变类型,因此您无法对其进行变更。因此,不可能做你提出的建议。
做出你提出的建议的更好方法是使用函数而不是单个表达式。可以多次调用函数,生成不同的对象。
:x