【问题标题】:Function modifying argument Julia函数修改参数 Julia
【发布时间】:2018-11-19 15:05:49
【问题描述】:

我有一个可变复合类型,

 mutable struct MyType

      x::Array{Float64}

 end

我有一个函数,我想修改它,

 function f(z::MyType)

      newx = z.x + 1
      z.x = newx

      return z

 end

这似乎不适用于更新 z。我错过了什么?

【问题讨论】:

    标签: julia


    【解决方案1】:

    z.x 是一个数组,所以必须写 z.x .+ 1(注意多余的点)来表示逐元素添加。

    function f(z::MyType)
          newx = z.x .+ 1
          z.x = newx
          return z
     end
    

    这个函数确实更新z:

    julia> z = MyType(rand(1:10, 4))
    MyType([10.0, 7.0, 2.0, 2.0])
    
    julia> f(z)
    MyType([11.0, 8.0, 3.0, 3.0])
    
    julia> z
    MyType([11.0, 8.0, 3.0, 3.0])
    
    julia> @btime f($z);
      886.115 ns (4 allocations: 208 bytes)
    

    分配是(至少)从它分配一个新数组newxz.x 的副本,其中每个元素都增加一个)这一事实来理解的,然后将其设置为分配给@的新数组987654328@。之前分配给 z.x 的原始数组现在已丢失(并将被 gc'ed)。

    您大概想要做的是在不创建中间数组的情况下就地修改分配给z.x 的数组。这可以通过编写来实现

    function f(z::MyType)
          z.x .= z.x .+ 1 # or equivalently z.x .+= 1
          return z
    end
    

    注意 .= 而不是 = 就地分配(您可以考虑按元素分配)。这给了

    julia> @btime f($z);
      372.284 ns (2 allocations: 48 bytes)
    

    请注意,您也可以写得更短

    f(z::MyType) = (z.x .+= 1; z)
    

    【讨论】:

    • 我知道 - 这只是示例代码,显示我正在进行更新(我正在执行的操作要复杂得多)。但问题不在于 RHS 不是正确的表达式,而在于它没有更新对象。
    • 你的例子太小了,因为它确实更新了对象(在你添加了额外的点之后)。我建议您提供一个实际显示“损坏”行为的最小示例。
    • 我对我的答案进行了相当多的重构。也许这有帮助。尽管如此,这两种方法都会更新z。这样做的效率更高。
    猜你喜欢
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 2016-05-16
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多