2016-04-17 18 views
6

Sono abbastanza nuovo per Elixir e per i linguaggi di programmazione funzionale in generale.Elixir - Metodo di chiamata sul modulo con nome String

In Elixir, voglio chiamare una funzione specifica sui moduli, dato il nome del modulo come stringa.

Ho il seguente codice (molto male) di lavoro, che fa più o meno quello che voglio:

module_name = elem(elem(Code.eval_file("module.ex", __DIR__), 0), 1) 
apply(module_name, :helloWorld, []) 

Questo (almeno se ho capito bene) compila il modulo (già compilato) di module.ex nella directory corrente. Sto estraendo il nome dei moduli (non come una stringa, non so quale sia il tipo di dati in realtà) tra le due tuple e eseguo il metodo helloWorld su di esso.

Ci sono due problemi con questo codice:

  1. stampa un avviso come redefining module Balance. Certamente non voglio che ciò accada in produzione.

  2. AFAIK questo codice compila module.ex. Ma poiché module.ex è già compilato e caricato, non vuole che ciò accada.

Non ho bisogno di chiamare i metodi su questi moduli per nomefile, il nome del modulo sarebbe ok anche. Ma deve essere dinamico, ad es. inserendo "Book" sulla riga di comando, dopo aver verificato se il modulo esiste, chiamare la funzione Book.helloWorld.

Grazie.

risposta

9

Bene, questo è dove chiedere aiuto: lo capirai da solo nel momento in cui lo chiedi. ;)

Basta usare apply(String.to_existing_atom("Elixir.Module"), :helloWorld, []) ora. (forse il nome "Modulo" non è consentito, non lo so)

+2

Piccola nota: si consiglia di utilizzare to_existing_atom quando possibile. Gli atomi non sono raccolti! –

+0

Grazie! Non sapevo che gli atomi non sono spazzatura raccolti. Modificherà la mia risposta. – lschuermann

1

Si noti inoltre che il nome di un modulo è un atomo, quindi non è in genere necessario eseguire String.to_existing_atom. Considerate questo codice:

defmodule T do 
    def first([]), do: nil 
    def first([h|t]), do: h 
end 

In questo caso si può semplicemente fare la applicano in questo modo:

apply(T,:first,[[1,2,3]]) 
#=> 1 

O questo esempio (elenco che segue è l'elisir List modulo):

apply(List,:first,[[1,2,3]]) 
#=> 1 

Intendo dire che se si conosce il nome del modulo, non è necessario passarlo come stringa e quindi convertire la stringa in un atomo esistente. Basta usare il nome senza virgolette.

+0

Sì, è assolutamente corretto.Ma nel mio caso, era l'obiettivo di rendere dinamico il nome del modulo. Naturalmente, se si conosce il nome del modulo, funzionerebbe anche questo. – lschuermann

6

Nota che è sempre necessario aggiungere un prefisso ai moduli con "Elisir".

defmodule Test do 
    def test(text) do 
    IO.puts("#{text}") 
    end 
end 

apply(String.to_existing_atom("Elixir.Test"), :test, ["test"]) 

stampe "test" e ritorna {}: ok

Problemi correlati