Le nom de la structure à instancier sera passé par l'appelant à mon programme. Ensuite, je devrais instancier la structure correspondante pour la même chose pour un traitement ultérieur.
Par exemple, si la structure est définie comme ceci
function load(struct_name::AbstractString) if struct_name == "A" return A() elseif struct_name == "B" return B() elseif ..... # and so on end end
et que j'ai une fonction définie comme
struct A end
cela fonctionnera. Mais y a-t-il un moyen plus direct comme return struct_name ()
au lieu d'avoir n nombre d'instructions if else? Je vois que Julia soutient la réflexion. Comment cela peut-il être utilisé pour prendre en charge le cas d'utilisation ci-dessus?
3 Réponses :
Je recommanderais de ne pas le faire dans le code de production, mais vous pouvez faire ce qui suit:
function load(struct_name::AbstractString) invoke(eval(Symbol(struct_name)),Tuple{}) end
strut_name
via eval
obtiendra résolu dans la portée globale du module.
Il est plus sûr d'utiliser un dictionnaire comme @EPo le suggère.
Merci @ Bogumił Kamiński, cela fonctionne comme requis. Quelles sont les précautions / inconvénients à prendre en compte lors de son utilisation?
En fait, l'utilisation de Symbol
rend eval
beaucoup plus sûr dans ce cas que eval
par exemple. Python alors que nous demandons à Julia de rechercher une liaison à ce symbole. Cependant, d'autres précautions s'appliquent - c'est-à-dire qu'il est lent lui-même, il n'est pas de type stable, il est résolu dans la portée globale (et peut-être que vous pourriez avoir une liaison à ce nom dans la portée locale également). En général - dans la plupart des cas, c'est un signe que vous pourriez utiliser un autre design.
Un exemple de répartition basée sur un dictionnaire. Dict ("a" => A, "b" => B) [tag]
sélectionne un constructeur et ()
l'appelle.
struct A end struct B end function dispatch(tag) return Dict("a" => A, "b" => B)[tag]() end @assert dispatch("a") == A()
Si vous vous souciez des valeurs par défaut pour gérer les paramètres inattendus, par exemple dispatch ('zzz')
,
vous pouvez faire appel à get ()
.
En guise de remarque sur les risques de eval ()
, il existe une petite collection de références d'avertissement puissantes dans un question Python voisine . En bref, eval ()
est une grande faille de sécurité et une «odeur» (signe d'avertissement) pour une conception douteuse d'un programme.
Merci pour vos contributions! En parcourant les liens, je comprends que l'utilisation de eval () est un risque de sécurité pour les problèmes d'injection de code, où n'importe quelle chaîne pourrait être envoyée pour instanciation. Donc, pour l'instant, je vais utiliser les instructions if else elles-mêmes qui n'ont pas ce problème, et voir également si elles sont vraiment nécessaires et qu'il n'y a pas d'autre alternative.
Un modèle simple à écrire que vous pourriez envisager est Dict (Symbol (fun) => fun for fun in [sin, cos, abs])
.
Et pour avoir des chaînes comme clés Dict (string (Symbol (fun)) => fun for fun in [sin, cos, abs])
.
Vous pouvez utiliser une macro à la place:
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
Considéré comme un dictionnaire? Aussi, qu'est-ce que la réflexion?
@EPo Reflection permet essentiellement d'inspecter les types et méthodes définis au moment de l'exécution sans connaître les noms des types et des méthodes au moment de la compilation. Dans des langages tels que Java, il permet également l'instanciation d'objets. Par exemple, voir ici: stackoverflow.com/questions/9886266/...
@EPo, comment utiliserais-je un dictionnaire dans ce cas? Notez que je ne veux pas instancier toutes les structures et les conserver dans le Dict, mais seulement instancier celle requise telle que passée à la fonction.
Vous pouvez appeler les constructeurs en fonction de la recherche dans le dictionnaire, mais généralement jouer avec ce type de répartition est risqué et indique généralement que quelque chose ne va pas dans la conception des autres parties du programme (ou des structures de données), alors peut-être vaut-il la peine finissez par rechercher une telle fonctionnalité dans le contexte de votre appelant et comment le résultat est utilisé.
Veuillez voir le petit exemple ci-dessous.
Il s'agit à peu près d'un double de stackoverflow.com/questions/34016768/...