2015-07-11 6 views
6

Sto ottenendo l'errore di compilazione:Come usare le parentesi per i generici?

angolo staffa la notazione non è stabile quando utilizzato con il Fn famiglia di tratti, usare le parentesi [E0215]

Cosa significa? Come faccio a "usare le parentesi"?

use std::hash::Hash; 
use std::collections::HashMap; 

struct MemoedFun<A, R> { 
    fun: fn(&A) -> R, 
    map: HashMap<A, R>, 
} 

fn memoize<A: Eq + Hash, R>(fun: fn(&A) -> R) -> MemoedFun<A, R> { 
    MemoedFun { 
     fun: fun, 
     map: HashMap::new(), 
    } 
} 

impl<'a, A, R> FnOnce<A> for &'a MemoedFun<A, R> { 
    type Output=&'a R; 
} 

risposta

8

Ci sono diversi problemi con il codice.

Prima di tutto, non è possibile utilizzare i tratti Fn* direttamente nella ruggine stabile. Ciò include 1) l'uso della notazione tra parentesi angolari e 2) l'implementazione di questi tratti. Tuttavia è possibile abilitare un flag di funzionalità per entrambe queste cose in Rust instabile.

In secondo luogo, se si utilizza parentesi angolari per i tratti di chiusura, è necessario utilizzare tuple per gli argomenti, anche se c'è un solo argomento:

FnOnce<(A,)> 

In terzo luogo, il messaggio di errore è che invece di FnOnce<(T, U), Output=V> voi dovrebbe scrivere FnOnce(T, U) -> V. Questo è ciò che si intende nel messaggio "uso di parentesi". Sono d'accordo che questo messaggio è fuorviante qui perché non è possibile implementare Fn quando è scritto in questo modo a causa di tipi associati. Immagino che l'errore sull'implementazione dei tipi Fn dovrebbe avere la precedenza su questo errore.

In quarto luogo, non sarà possibile eseguire ciò che si desidera (una funzione di memoizzazione supportata da una mappa hash) quando si utilizza &'a MemoedFun<A, R> perché è necessario un puntatore mutabile per aggiornare la mappa. È necessario implementare FnOnce per &'a mut MemoedFun<A, R>:

impl<'a, A: Eq + Hash, R> FnOnce<(A,)> for &'a mut MemoedFun<A, R> { 
    type Output = &'a R; 

    extern "rust-call" fn call_once(self, (arg,): (A,)) -> &'a R { 
     if self.map.contains_key(&arg) { 
      &self.map[&arg] 
     } else { 
      let r = (self.fun)(&arg); 
      self.map.entry(arg).or_insert(r) 
     } 
    } 
} 

E, infine, il codice risultante si sarebbe dovuto scrivere per utilizzare questo memoizer non è abbastanza. Non è possibile utilizzare la sintassi funzione sul vostro "funzione" per qualche motivo, quindi è necessario utilizzare call_once() direttamente:

fn computer(x: &i32) -> i32 { 
    println!("Computing for {}", x); 
    -*x 
} 

let mut f = memoize(computer); 

println!("f(10): {}", (&mut f).call_once((10,))); 
println!("f(10): {}", (&mut f).call_once((10,))); 
println!("f(42): {}", (&mut f).call_once((42,))); 

(provarlo here)

C'è una ragione per cui implementazione Fn* tratti manuale non è stabilizzato, dopo tutto.

+0

C'è un bug di ruggine per questo messaggio di errore fuorviante? Non ho trovato nulla con una ricerca ingenua, – llogiq

+0

Non ne ho trovato neanche uno, quindi immagino abbia senso crearne uno. –

+0

Cosa significa FnOnce (T, U) -> V? Non riesco a trovare una descrizione di questa sintassi. Output è una parola chiave speciale? – dspyz