2015-05-27 13 views
6

Sto provando a selezionare un algoritmo digest (da rug-crypto) basato su una stringa di configurazione. In Python o JavaScript, diciamo, probabilmente sarei utilizzare la reflection per arrivare a questo:Idiomatic alternative to reflection

getattr(Digest, myAlgorithm) 

... ma da quello che ho potuto Google, questa non è delle migliori pratiche in un linguaggio come Ruggine (in più non ho trovato dettagli su come potrebbe essere fatto). Il mio primo pensiero è stato quello di utilizzare un pattern match:

let mut digest = match myAlgorithm { 
    "sha256" => Sha256::new(), 
    ... 
}; 

Tuttavia, questo non funziona perché, mentre tutti i rami della partita implementano lo stesso tratto, sono in ultima analisi, i tipi differenti. Inoltre, presumendo che ci fosse un modo per aggirare questo, è un sacco di problemi enumerare manualmente tutte queste opzioni nel codice.

Qual è il modo giusto per farlo in Rust?

+0

Sai di * tratti * in Rust? Sono utilizzati per specificare un'interfaccia comune a più implementazioni. –

risposta

7

Dal momento che tutti gli algoritmi implementano lo stesso tratto Digest, che offre tutto il necessario, si può box tutti gli algoritmi e convertirli in un comune Box<Digest>:

let mut digest: Box<Digest> = match my_algorithm { 
    "sha256" => Box::new(Sha256::new()), 
    ... 
}; 

Ora non si sa più quello che il tipo era, ma sai ancora che è un Digest.

Python e JavaScript eseguono il boxing (allocazione dinamica dell'heap) per te in background. Rust è molto schizzinoso su queste cose e quindi richiede che tu dichiari esplicitamente cosa intendi.

Sarebbe interessante avere una riflessione in Rust per poter enumerare tutti i tipi in ambito che implementano un tratto, ma un tale sistema richiederebbe un certo sforzo nel compilatore di ruggine e nel cervello dei membri della comunità ruggine . Non aspettarti presto.

+0

Grazie: quindi i tratti sono un po 'come i typeclass Haskell? Ad ogni modo, questo risolve il problema del controllo dei tipi, ma ora quando provo ad usarlo, ottengo che 'the trait \' crypto :: digest :: Digest \ 'non è implementato per il tipo \' Box \ '' – Xophmeister

+0

eh ... è strano ... come un trucco puoi provare a ottenere un riferimento all'oggetto interno usando '& * digest'. Ma senza conoscere ulteriori dettagli su ciò che hai provato, non posso aiutarti. –

+0

@Xophmeister Qual è la definizione di 'Digest'? Il codice ker fornito funzionerà solo se il tratto è [sicuro per gli oggetti] (https://huonw.github.io/blog/2015/01/object-safety/). –