Elixir - Ruft private Funktion dynamisch auf

8

Ich habe Kernel.apply/3 gefunden, was den dynamischen Aufruf einer öffentlichen Methode in einem Modul ermöglicht, indem die Methode als Atom angegeben wird, z. result = apply(__MODULE__, :my_method, [arg]) wird in result = my_method(arg)

übersetzt

Was mich verwirrt, ist eine Art, eine private Methode zu nennen; Code wie folgt gegeben:

%Vor%

Ich würde erwarten, dass MyModule.do_priv(:something_private, [1]) zulässig ist, da es sich um einen Aufruf einer privaten Methode innerhalb des Moduls handelt. Ich kann mir vorstellen, dass Elixir unter der Haube Erlangs "apply / 3" verwendet, und so wird uns dieser Ansatz wahrscheinlich nicht dorthin bringen.

Ich habe auch versucht, die Code.eval_quoted/3 -Methode zu verwenden, aber es scheint nicht einmal in der Lage zu sein, eine hardcodierte private Methode aufzurufen (und daher keine Zeit für die Erstellung der AST von Hand, anstatt quote do as zu verwenden) unten - obwohl das eine Option ist, wenn jemand sieht, wie es funktioniert:

%Vor%

Auch hier ist der Zugriff auf eine private Funktion innerhalb des enthaltenen Moduls möglich, also würde ich erwarten, dass dies zulässig ist. Es ist möglich, dass ich den __ENV__ Parameter zu eval_quoted

einfach nicht verstehe

Die einzige funktionierende Lösung ist momentan, defp in def zu ändern, was eine gute Lösung für meinen persönlichen Code ist; Aber da ich Code schreibe, der andere Programmierer unterstützt, die es interessiert, würde ich gerne eine Lösung finden.

Ich bin offen für andere Ansätze, aber ich bin persönlich ratlos, wie ich das erreichen kann.

    
Chris Meyer 08.03.2015, 17:55
quelle

3 Antworten

6

Zunächst sollten Sie wissen, dass f() , das in einem MyModule-Modul aufgerufen wird, nicht dasselbe ist wie MyModule.f() , das an derselben Stelle aufgerufen wird. Siehe Ссылка

Sie können nur private Funktionen aufrufen f() style. Diese Aufrufe werden auch vom Compiler überprüft - wenn die Funktion nicht existiert, erhalten Sie einen Kompilierungsfehler. Wenn Sie MyModule.f() an derselben Stelle verwenden, erhalten Sie nicht einen Kompilierungsfehler, da diese Aufrufe nur zur Laufzeit überprüft werden (selbst wenn Sie das Modul von selbst aufrufen) und der Effekt (AFAIK ) Das gleiche wie wenn Sie MyModule.f() von einem anderen Modul aus aufrufen würden - das Modul wird in Runtime gesucht und Sie können nur exportierte (öffentliche) Funktionen aufrufen.

Daher können Sie nicht private Funktionen auf andere Weise aufrufen als nur eine einfache f() . apply(mod,fun,[]) ist äquivalent zu mod.fun.() style - das Modul wird zur Laufzeit aufgelöst und auf private Funktionen kann nicht zugegriffen werden.

Sie können alle Varianten in diesem Beispiel selbst ausprobieren: Ссылка

Sie können jetzt sehen, dass Aufrufe an private Funktionen zur Kompilierungszeit immer bekannt sein müssen, so dass Sie nicht einmal eval_quoted magic oder irgendeine andere Magie verwenden können, um sie zu "dynamic" zu machen ...

Sasa Juric's Ratschlag, @doc false zu verwenden, ist die richtige Lösung.

    
Miroslav Prymek 09.03.2015, 12:06
quelle
7

AFAIK, das private Funktionen dynamisch aufruft, ist in Erlang (und daher nicht in Elixir) nicht möglich. Wenn Sie eine dynamische Verteilung durchführen müssen, können Sie eine Mehrsatzfunktion in Betracht ziehen. Ein künstliches Beispiel (sicherlich ein schlechtes Beispiel, aber ich kann mir keinen besseren Geldautomaten vorstellen):

%Vor%

Eine andere Alternative besteht darin, Ihre Funktion öffentlich zu machen, aber mit @doc false anzugeben, dass sie intern ist - also nicht dazu gedacht ist, von Kunden öffentlich verwendet zu werden. Sie können auch erwägen, solche Funktionen in ein separates Modul zu verschieben und das gesamte Modul mit @moduledoc false als intern zu markieren. Beide Ansätze werden gelegentlich im Elixir-Code verwendet.

Ich würde jedoch vorschlagen, einfach zu beginnen und Mustervergleiche und Funktionen mit mehreren Klauseln zu verwenden. Wenn der Code komplexer wird, würde ich dann andere Optionen in Betracht ziehen.

    
sasajuric 08.03.2015 19:40
quelle
2

Verwenden von Makros

Sie können Macros verwenden, um private Methoden innerhalb desselben Moduls dynamisch aufzurufen. Hier ist ein einfaches Makro, das das erreicht:

%Vor%

Um es in Ihrem Modul aufzurufen, können Sie dies tun (Denken Sie daran, das Makro vor dem Aufruf zu definieren!):

%Vor%

local_apply würde beim Aufruf auf den gewünschten Methodenaufruf mit Argumenten erweitert - aber nur zur Kompilierzeit - das bedeutet, dass Sie das Makro zur Laufzeit nicht dynamisch auf Ihre Funktionsaufrufe erweitern können.

    
Sheharyar 13.07.2017 16:07
quelle

Tags und Links