在 Julia 中从另一个结构构造结构时出现 StackOverflowError

问题描述 投票:0回答:1

当我尝试从另一个先前存在的结构对象构建结构对象(其中一个参数依赖于其他参数)时,我得到一个

StackOverflowError

我定义了一个如下所示的类型:

using Parameters
julia> @with_kw struct A
          a1 = 0
          a2 = 0
          b = (; b1 = a1, b2 = a2)
       end

由此我可以构建一个对象

A

julia> anobject = A(; a1 = 1, a2 = 3)

有:

julia> anobject.b = (; b1 = 1, b2 = 3)

现在,我需要从第一个对象构建第二个对象,并更新一些值:

julia> object2 = A(anobject; a1 = 5)

但这会导致:

julia> object2.a1 = 5
julia> object2.a2 = 3
julia> object2.b = (; b1 = 1, b2 = 3)

b
尚未更新。

我尝试定义一个构造函数:

julia> A(a::A; a1 = 0, kw...) = A(a; a1 = a1, b = (; a.b..., b1 = a1), kw...)

但是使用它时,会产生

StackOverflowError

julia> object3 = A(anobject; a1 = 5)
ERROR: StackOverflowError:

当然我不明白它来自哪里,也没有找到任何相关文档。正确的方法是什么?

struct types constructor julia stack-overflow
1个回答
0
投票

您的

A
构造函数正在调用自身,而不是使用关键字调用默认的
A
构造函数。

一个快速更改是使用关键字调用默认的

A
构造函数:

import Parameters: @with_kw

@with_kw struct A
             a1 = 0
             a2 = 0
             b = (; b1 = a1, b2 = a2)
         end

A(a::A; a1 = 0) = A(a1 = a1, a2 = a.a2, b = (; a.b..., b1 = a1))

obj1 = A(; a1 = 1, a2 = 3)
# A
#   a1: Int64 1
#   a2: Int64 3
#   b: @NamedTuple{b1::Int64, b2::Int64}

obj1.b
# (b1 = 1, b2 = 3)

obj2 = A(obj1; a1 = 5)
# A
#   a1: Int64 5
#   a2: Int64 3
#   b: @NamedTuple{b1::Int64, b2::Int64}

obj2.b
# (b1 = 5, b2 = 3)

一个复杂的更改是使用像

NamedTupleTools
这样的包将旧结构转换为
NamedTuple
,将其与新的关键字参数合并,然后使用这些关键字调用默认的
A
构造函数。

import Parameters: @with_kw
import NamedTupleTools: merge, ntfromstruct

@with_kw struct A
             a1 = 0
             a2 = 0
             b = (; b1 = a1, b2 = a2)
         end

function A(a::A; kw...) 
  a_nt = merge(ntfromstruct(a), NamedTuple(kw))
  b_nt = (; b1 = a_nt.a1, b2 = a_nt.a2)
  A(; merge(a_nt, (; b = b_nt))...)
end

obj1 = A(; a1 = 1, a2 = 3)
# A
#   a1: Int64 1
#   a2: Int64 3
#   b: @NamedTuple{b1::Int64, b2::Int64}

obj1.b
# (b1 = 1, b2 = 3)

obj2 = A(obj1; a1 = 5)
# A
#   a1: Int64 5
#   a2: Int64 3
#   b: @NamedTuple{b1::Int64, b2::Int64}

obj2.b
# (b1 = 5, b2 = 3)

© www.soinside.com 2019 - 2024. All rights reserved.