Юлия: Самореферентные и рекурсивные типы - PullRequest
3 голосов
/ 11 апреля 2020

То, что я пытаюсь сделать, не очень прямолинейно, возможно, будет проще, если я начну с результата, а затем объясню, как я пытаюсь туда добраться.

У меня есть структура с двумя полями:

struct data{T}
    point::T
    mat::Array
end

То, что я хотел бы сделать, это вложить это и сделать полевую ссылку самореферентной, чтобы получить что-то вроде этого:

data{data{Int64}}(data{Int64}(1, [1]), [1])

Внешний тип не должен хранить [ 1] но ссылка на самый внутренний коврик. Я не уверен, имеет ли это смысл или даже возможно. Мат поля должен хранить один и тот же большой массив несколько раз.

Я пробовал что-то вроде этого (n - это число вложенных типов.

struct data{T}
    point::T
    g::Array
    function D(f, g, n)
        for i = 1:n
            (x = new{T}(f, g); x.f = x)
        end
    end
end 

Опять же, я не уверен, что я понимаю себя достаточно ссылочных конструкторов, или, если это возможно. Любая помощь / разъяснения будет признательна, спасибо!

Ответы [ 2 ]

3 голосов
/ 11 апреля 2020

Точная схема будет зависеть от того, чего вы хотите достичь, но вот один пример:

struct Data{V, A <: AbstractArray{V}, T} 
    mat::A
    point::T

    Data(mat::A, point::T = nothing) where {V, A <: AbstractArray{V}, T} =
        new{V,A,T}(mat,point)
end

Использование

julia> d0 = Data([1,2,3])
Data{Int64,Array{Int64,1},Nothing}([1, 2, 3], nothing)

julia> d1 = Data([1.0,2.0],d0)
Data{Float64,Array{Float64,1},Data{Int64,Array{Int64,1},Nothing}}([1.0, 2.0], Data{Int64,Array{Int64,1},Nothing}([1, 2, 3], nothing))

Советы:

  1. Никогда не используйте нетипизированные контейнеры. Следовательно, когда вы хотите сохранить Array, вам нужно иметь его тип в вашем определении struct.

  2. Использовать имена, начинающиеся с заглавной буквы, для struct s

  3. Предоставьте конструкторам, чтобы ваш API читался

Последнее, но не менее важное. Если вы хотите иметь несколько уровней вложенности для такой структуры, время компиляции значительно возрастет. В этом случае обычно лучше использовать однородные типы. В таком сценарии ios вы могли бы использовать вместо этого, возможно, тип Union s (объединения Юлия небольшого числа типов быстрые в Юлии).

3 голосов
/ 11 апреля 2020

Исходя из вашего описания, data выглядит как очень общая оболочка. Может быть, вы можете попробовать что-то вроде этого:

mutable struct Wrap{T}
    w::Wrap{T}
    d::T
    function Wrap(d::T) where T
        w = new{T}()
        w.d = d
        w
    end
end

function Wrap(d, n::Int)
    res = Wrap(d)
    cur = res
    for _ in 1:n-1
        cur.w = Wrap(d)
        cur = cur.w
    end
    res
end

Wrap([1], 4)
# Wrap{Array{Int64,1}}(Wrap{Array{Int64,1}}(Wrap{Array{Int64,1}}(Wrap{Array{Int64,1}}(#undef, [1]), [1]), [1]), [1])
...