Как создать экземпляр структуры в Julia, где у меня есть имя структуры в строковой переменной? - PullRequest
2 голосов
/ 18 мая 2019

Имя структуры для создания экземпляра будет передано вызывающей программой моей программе.Затем мне нужно создать экземпляр соответствующей структуры для той же самой для дальнейшей обработки.

Например, если структура определена следующим образом

struct A end

и у меня есть функция, определенная как

function load(struct_name::AbstractString)
    if struct_name == "A"
        return A()
    elseif struct_name == "B"
        return B()
    elseif ..... # and so on
    end
end

это будет работать.Но есть ли более прямой способ, например return struct_name(), вместо n операторов if else?Я вижу, что Юлия поддерживает рефлексию.Как это можно использовать для поддержки вышеуказанного варианта использования?

Ответы [ 3 ]

2 голосов
/ 18 мая 2019

Я бы порекомендовал не делать это в рабочем коде, но вы можете сделать следующее:

function load(struct_name::AbstractString)
    invoke(eval(Symbol(struct_name)),Tuple{})
end

strut_name через eval будет разрешено в глобальной области видимости модуля.

Безопаснее использовать словарь, как предложено @EPo.

1 голос
/ 18 мая 2019

Пример отправки по словарю. Dict("a" => A, "b" => B)[tag] выбирает конструктор, а () вызывает его.

struct A end
struct B end

function dispatch(tag)
   return Dict("a" => A, "b" => B)[tag]()
end

@assert dispatch("a") == A()

Если вы заботитесь о значениях по умолчанию для обработки неожиданного параметра, например dispatch('zzz'), Вы можете обратиться за помощью к get().

В качестве дополнительного примечания о рисках eval() в соседнем соседнем вопросе о Python имеется небольшая коллекция мощных ссылок на предупреждения. Короче говоря, eval() - это большая дыра в безопасности и «запах» (предупреждающий знак) для сомнительного дизайна программы.

0 голосов
/ 19 мая 2019

Вместо этого вы можете использовать макрос:

julia> module Load
       export @load

       macro load(struct_name::Symbol)
           return :($(esc(struct_name))())
       end

       end
Main.Load

julia> using Main.Load: @load

julia> struct A end

julia> struct B end

julia> @load A
A()

julia> @macroexpand @load B
:(B())

julia> @load C
ERROR: UndefVarError: C not defined
Stacktrace:
 [1] top-level scope at none:0
...