英文:
Chained variable assignment in Julia
问题
我对Julia如何处理以下代码块感到困惑:
a = [1,2,3]
a .= a/2 .= o = a .* 2
对于'a'和'o'的输出都是[2,4,6]。然而,我不明白为什么'a'的结果与我使用a .= a*2的结果相同。a/2被视为变量并传递给数组[2,4,6](即a*2的结果)吗?然后这个“变量”a/2被传递给a吗?我本来希望a保持为[1,2,3]。我不确定Julia是否以特定顺序执行这些操作。
英文:
I'm puzzled by how Julia handles the block of code below:
a = [1,2,3]
a .= a/2 .= o = a .* 2
The output for both 'a' and 'o' is [2,4,6]. However, I don't understand why the result for 'a' is the same as if I had used a .= a*2. Is a/2 treated as a variable and passed the array [2,4,6] (the result of a*2)? And then this "variable" a/2 is passed to a? I would have expected a to have stayed as [1,2,3]. I'm uncertain as to whether Julia executes these operations in a specific order.
答案1
得分: 2
表达式 a / 2 创建了一个新的数组,最初包含您期望的值 ([1,2,3]),然而,该数组的内容立即被右侧数组的广播赋值所覆盖。
让我们分解整个表达式,Julia 可以帮助我们:
julia> :(a .= a/2 .= o = a .* 2)
:(a .= (a / 2 .= (o = a .* 2)))
通过查看在打印 Expr 时插入的括号,我们可以更清楚地看到子表达式。正如您所看到的,顶部表达式是 a .= (右侧所有内容的结果)。
让我们在 REPL 中对其进行评估:
julia> o = a .* 2
3-element Vector{Int64}:
2
4
6
julia> a / 2 .= (o = a .* 2)
3-element Vector{Float64}:
2.0
4.0
6.0
julia> a .= (a / 2 .= (o = a .* 2))
3-element Vector{Int64}:
2
4
6
正如您所看到的,由 a / 2 创建的数组是 Float64 数组,因此在放入 a 时被转换成 Int64,然后再次转换回来。
我们可以通过使用 Meta.show_sexpr 使右侧表达式更加明确。
julia> :(a/2 .= o = a .* 2) |> Meta.show_sexpr
(:.=, (:call, :/, :a, 2), (:(=), :o, (:call, :.*, :a, 2)))
让我们为清晰起见添加一些空格:
(:.=,
(:call, :/, :a, 2),
(:(=),
:o,
(:call, :.*, :a, 2)))
因此,此表达式是将值广播分配给调用参数 a 和 2 上的 / 函数返回的值。分配的值是赋值 o = a * 2 返回的值。
英文:
The expression a / 2 creates a new array which initially contains the values you expect ([1,2,3]) however the contents of that array are immediately overwritten by a broadcast assignment with the contents in the right hand side array.
Let's break down the entire expression, Julia can help us:
julia> :(a .= a/2 .= o = a .* 2)
:(a .= (a / 2 .= (o = a .* 2)))
By looking at the parentheses inserted when the Expr is printed we see the subexpressions a bit more clearly. As you can see the top expression is a .= (result of everything on RHS).
Let's evaluate it in the REPL:
julia> o = a .* 2
3-element Vector{Int64}:
2
4
6
julia> a / 2 .= (o = a .* 2)
3-element Vector{Float64}:
2.0
4.0
6.0
julia> a .= (a / 2 .= (o = a .* 2))
3-element Vector{Int64}:
2
4
6
As you can see the array created by a / 2 is a Float64 array and the values are therefore converted and then converted back to Int64 when put into a.
We can make the right hand side expression even more explicit by using Meta.show_sexpr.
julia> :(a/2 .= o = a .* 2) |> Meta.show_sexpr
(:.=, (:call, :/, :a, 2), (:(=), :o, (:call, :.*, :a, 2)))
let's add some whitespace for clarity:
(:.=,
(:call, :/, :a, 2),
(:(=),
:o,
(:call, :.*, :a, 2)))
so this expression is broadcast assigning to the value that is returned by calling the / function on the arguments a and 2. The value that is assigned is what the assignment o = a * 2 returns.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论