构造函数中的StackOverflowError错误


#1

我定义了下面这个结构:

struct PolyXray{N, T <:AbstractFloat} <:AbstractXray
    wavelength::SVector{N, T}
    intensity::SVector{N, T}
    function PolyXray(wavelength, intensity)
        @assert all(wavelength .> 0) "Legal wavelengthes"
        @assert all(intensity .>= 0) "Legal intensities"
        new{length(wavelength), eltype(wavelength)}(wavelength, intensity)
    end
end

const PolyXray(data::AbstractVector{<:AbstractFloat}, intensity::AbstractVector{<:AbstractFloat}) = 
    PolyXray(SVector{length(data)}(data), SVector{length(intensity)}(intensity))

其中SVectorStaticArrays包中的类型,满足SVector{N, T} <: AbstractVector{T}
我按照下面这个程序来构造一个PolyXray:

PolyXray([1.,2.,3.],[1.,2.,3.])

会出现下列错误:

ERROR: StackOverflowError:
Stacktrace:
 [1] Type at /home/jasper/.julia/packages/StaticArrays/VyRz3/src/SArray.jl:23 [inlined]
 [2] Type at /home/jasper/.julia/packages/StaticArrays/VyRz3/src/SVector.jl:19 [inlined]
 [3] Type at /home/jasper/.julia/packages/StaticArrays/VyRz3/src/convert.jl:5 [inlined]
 [4] PolyXray(::StaticArrays.SArray{Tuple{3},Float64,1,3}, ::StaticArrays.SArray{Tuple{3},Float64,1,3}) at /home/jasper/DiffJulia/src/Xray.jl:75 (repeats 64963 times)
 [5] PolyXray(::Array{Float64,1}) at /home/jasper/DiffJulia/src/Xray.jl:79
 [6] top-level scope at none:0

看起来是在靠后的构造函数中不断迭代,并没有跳出。
我该怎么样才能解决这个问题呢?
环境是Linux mint 18.3 Sylvia,Julia 1.1.0


#2

SVector{2, Float64} <: AbstractVector{Float64}为true
所以猜测你后面定义的函数有问题,右边执行左边,左边又调用右边,就是在不停的死循环。
实际上你不要后面定义的函数,也可以运行的。


#3

谢谢,我明白你的意思。我其实做的目的是定义更加范用的函数,然后把范用的函数的参数给转换成SVector。要是想实现这个要求,需要怎么做呢?
Julia里面会有采用最专用的方法这一说吗?如果有最专用的要求的话,我在后面定义的函数中将参数类型转换成了SVector,按理就会执行我前面定义的构造函数,然而现在却只在我后面定义的函数中打转。


#4

Julia分派会找最接近的,你的构造函数any,svector肯定与abstract更接近。
这样你看看合不合你意,我也是初学,最优的搞法不知道是啥。但是这样运行没有问题。

struct PolyXray{N, T <:AbstractFloat}
    wavelength::SVector{N, T}
    intensity::SVector{N, T}
    function PolyXray{N, T}(wavelength, intensity) where {N, T <:AbstractFloat}
        @assert all(wavelength .> 0) "Legal wavelengthes"
        @assert all(intensity .>= 0) "Legal intensities"
        new{N, T}(wavelength, intensity)
    end
end

PolyXray(data::AbstractVector{T1}, intensity::AbstractVector{T2}) where{T1<:AbstractFloat, T2<:AbstractFloat} = 
    PolyXray{length(data), T1}(SVector{length(data), T1}(data), SVector{length(intensity),T1}(intensity))

或者写成这样

struct PolyXray{N, T <:AbstractFloat}
    wavelength::SVector{N, T}
    intensity::SVector{N, T}
    function PolyXray(wavelength::SVector{N, T}, intensity::SVector{N, T}) where {N, T<:AbstractFloat}
        @assert all(wavelength .> 0) "Legal wavelengthes"
        @assert all(intensity .>= 0) "Legal intensities"
        new{N, T}(wavelength, intensity)
    end
end

 PolyXray(data::AbstractVector{<:AbstractFloat}, intensity::AbstractVector{<:AbstractFloat}) = 
    PolyXray(SVector{length(data)}(data), SVector{length(data)}(intensity))

#5

你应该写一个专门针对 SVector 的内部构造函数来约束(默认的构造函数就是),外部构造函数只应该用来提供便利。Julia 会使用最专用的方法,可以看看关于方法设计的文档

struct PolyXray{N, T <:AbstractFloat}
    wavelength::SVector{N, T}
    intensity::SVector{N, T}
    function PolyXray(wavelength::SVector{N, T}, intensity::SVector{N, T}) where {N, T<:AbstractFloat}
        @assert all(wavelength .> 0) "Legal wavelengthes"
        @assert all(intensity .>= 0) "Legal intensities"
        return new{N, T}(wavelength, intensity)
    end
end

PolyXray(data::AbstractVector{T}, intensity::AbstractVector{T}) where {T <: AbstractFloat} =
    PolyXray(SVector{length(data), T}(data), SVector{length(data), T}(intensity))
PolyXray(data::AbstractVector{<:AbstractFloat}, intensity::AbstractVector{<:AbstractFloat}) =
    PolyXray(promote(data, intensity)...) # promote 确保元素类型相同
PolyXray(data::AbstractVector, intensity::AbstractVector{<:AbstractFloat}) =
    PolyXray(promote(data, intensity)...)
PolyXray(data::AbstractVector{<:AbstractFloat}, intensity::AbstractVector) =
    PolyXray(promote(data, intensity)...)
PolyXray(data::AbstractVector, intensity::AbstractVector) =
    PolyXray(SVector{length(data), Float64}(data), SVector{length(data), Float64}(intensity)) # 其它情况下数组类型转为 Float64