Julia 当我试图创建以矩阵作为字段的复合类型时,堆栈溢出

Julia 当我试图创建以矩阵作为字段的复合类型时,堆栈溢出,julia,Julia,在下面的代码中,我有一个复合类型,在我的实际代码中,有几个字段是矩阵。在这个例子中只有1。当我尝试构造复合类型时,我总是遇到堆栈溢出。以下是代码示例: struct Tables eij::Array{Float64,2} end Tables(eij::Array{Float64,2}) = Tables(eij) # works if this is commented out x = 5 # arbitrary matrix dimension e_ij = Arra

在下面的代码中,我有一个复合类型,在我的实际代码中,有几个字段是矩阵。在这个例子中只有1。当我尝试构造复合类型时,我总是遇到堆栈溢出。以下是代码示例:

struct Tables
    eij::Array{Float64,2}
end

Tables(eij::Array{Float64,2}) = Tables(eij) # works if this is commented out
x = 5   # arbitrary matrix dimension    
e_ij = Array{Float64,2}(undef,x,x)

for i=1:x
    for j=1:x
        e_ij[i,j] = i*j/2.3     #dummy numbers, but not the case in real code
    end
end

vdwTable = Tables([e_ij[i,j] for i=1:x,j=1:x])
我使用临时变量
e_ij
首先生成矩阵,因为我不希望复合
是可变的。因此,我的推理是,通过首先在伪变量(如
e_ij
)中生成表,我可以初始化我真正想要的不可变

如果我注释掉struct
Tables
的外部构造函数,它就会工作。但是,对于不同字段没有传递数据进行初始化的情况,我实际上希望有几个不同的外部构造函数。在这些情况下,我想给他们默认的矩阵

我得到的错误如下:
error:LoadError:stackoverflowererror:
on
vdwTable=Tables([e_ij[i,j]表示i=1:x,j=1:x])

定义复合类型时,会自动定义内部构造函数,因此:

struct Tables
    eij::Array{Float64,2}
end
相当于:

struct Tables
    eij::Array{Float64,2}
    Tables(eij::Array{Float64,2}) = new(eij)
end
Tables(eij::Any) = Tables(eij)
定义此外部构造函数时

Tables(eij::Array{Float64,2}) = Tables(eij)
你会妨碍内部构造函数。外部构造函数只是递归地调用自身,直到出现堆栈溢出

另一方面,这样做

Tables(eij) = Tables(eij)
实际上相当于:

struct Tables
    eij::Array{Float64,2}
    Tables(eij::Array{Float64,2}) = new(eij)
end
Tables(eij::Any) = Tables(eij)
所以当你后来打电话的时候

vdwTable = Tables([e_ij[i,j] for i=1:x,j=1:x])
然后它将忽略外部构造函数,因为有一个更具体的方法匹配,即内部构造函数。所以,特定的外部构造函数是非常无用的,它要么被忽略,要么将递归直到堆栈溢出

最简单的解决方案是:不要创建外部构造函数。如果确实需要外部构造函数来强制执行某些条件,请确保它不会因为具有相同的类型签名而影响内部构造函数。比如说,

Tables() = Tables(zero(5, 5))
应该有用

不过,我可能会这样做:

struct Tables
    eij::Array{Float64,2}
    Tables(eij=zeros(5, 5)) = new(eij)
end
对于第二个示例,使用两个字段,您可以尝试以下操作:

struct Tables
    eij::Array{Float64,2}
    sij::Array{Float64,2}
    Tables(eij=zeros(5,5), sij=zeros(5,5)) = new(eij, sij)
end
如果可能,您的输入将转换为
Float64
矩阵,否则将引发异常。

给出了正确的解释so+1。我只想补充一条小评论(不是对问题的回答,而是与我的经验相关的东西),这条评论太长了

当您忽略指定内部构造函数时,Julia会自动定义一个内部构造函数和一个外部构造函数:

julia> struct Tables
           eij::Array{Float64,2}
       end

julia> methods(Tables)
# 2 methods for generic function "(::Type)":
[1] Tables(eij::Array{Float64,2}) in Main at REPL[1]:2
[2] Tables(eij) in Main at REPL[1]:2
julia> struct Tables
           eij::Array{Float64,2}
           Tables(eij::Array{Float64,2}) = new(eij)
       end

julia> methods(Tables)
# 1 method for generic function "(::Type)":
[1] Tables(eij::Array{Float64,2}) in Main at REPL[1]:3
定义内部构造函数时,会抑制外部构造函数的定义:

julia> struct Tables
           eij::Array{Float64,2}
       end

julia> methods(Tables)
# 2 methods for generic function "(::Type)":
[1] Tables(eij::Array{Float64,2}) in Main at REPL[1]:2
[2] Tables(eij) in Main at REPL[1]:2
julia> struct Tables
           eij::Array{Float64,2}
           Tables(eij::Array{Float64,2}) = new(eij)
       end

julia> methods(Tables)
# 1 method for generic function "(::Type)":
[1] Tables(eij::Array{Float64,2}) in Main at REPL[1]:3
因此,这些案例并非100%等同。自动生成的外部构造函数的目的是在可能的情况下对其参数执行自动转换,例如(这是第一种情况下的结果-未定义内部构造函数时):


而在第二种情况下,相同的调用会抛出一个方法错误。

我是基于一种类似的方法,我用于向量的复合类型,但是,我也使用参数类型。我认为参数化类型的使用使得在外部构造函数的左侧定义类型变得非常有效。。。但我不知道为什么。。。如果我把LHS放在Tables()或Tables(eij)中,它会工作……嗯。我实际上不知道默认的外部构造函数。但知道了这一点,我逐渐学到了一个教训:试着写尽可能少和简单的代码,看看它是否“正常工作”。然后根据需要添加方法。否则你只会妨碍你自己。这也是我的经验——朱莉娅大多数时候都有非常明智的默认值:)。有一种情况与参数类型相关,但它更高级,希望有一天能得到修复。这是一个很好的答案。问题:如果我希望默认的零矩阵与其他矩阵的大小相同,该怎么办?在内部构造函数中有这样做的方法吗?在实际代码中,直到运行时才知道矩阵的大小。真正的问题是,如果我有3个或更多的字段,每个字段都是矩阵,但有可能只有1个字段会传递给构造函数,那么如何使其他2个默认的零矩阵与传递的矩阵大小相同。内部构造函数:
表(eij=zeros(5,5),sij=zeros(size(eij))=new(eij,sij)