2015-05-03 29 views
5

Sto scrivendo un binding Rust per una libreria C. Implementa un'entità che può essere costruita da diverse entità di origine, eventualmente salvando alcuni riferimenti internamente. Voglio che il tipo Rust imponga una politica di proprietà sicura, quindi la struttura del wrapper è generica, parametrizzata dal tipo del riferimento memorizzato.Annotazione esplicita del tipo per costruttore generico di tipo generico

struct Foobar<T> { 
    origin: T, 
} 

Poi ho implementare alcuni costruttori per il mio tipo Foobar.

impl<T> Foobar<T> { 
    fn from_nowhere() -> Foobar<()> { 
     Foobar { origin:() } 
    } 

    fn from_orange<F>(orange: &mut F) -> Foobar<&mut F> 
     where F: Orange 
    { 
     Foobar { origin: orange } 
    } 

    fn from_callback<F>(callback: F) -> Foobar<F> 
     where F: FnMut(u64) -> u64 
    { 
     Foobar { origin: callback } 
    } 
} 

E qui arriva il problema: sia la struct che il costruttore sono parametrizzati in modo indipendente. Mentre il parametro del tipo di costruttore può essere dedotto dai suoi argomenti, il parametro struct type non viene utilizzato nel costruttore e non può essere dedotto. Così, il modo ingenuo chiamare un costruttore

let a = Foobar::from_nowhere(); 
let b = Foobar::from_orange(&mut fruit); 
let c = Foobar::from_callback(|x| x*x); 

confonde rustc:

rustgen.rs:43:13: 43:33 error: unable to infer enough type information about `_`; type annotations required [E0282] 
    rustgen.rs:43  let a = Foobar::from_nowhere(); 

Esso può essere risolto fornendo un certo tipo di parametro arbitrario:

let a = Foobar::<()>::from_nowhere(); 
let b = Foobar::<()>::from_orange(&mut fruit); 
let c = Foobar::<()>::from_callback(|x| x*x); 

... che è tutto tipi di brutto. Un altro modo per risolvere il problema sarebbe quello di trasformare i costruttori in funzioni libere, anche se sarebbe (un po ') non idiomatico.

La domanda è: mi manca qualcosa? Il design sembra essere difettoso in qualche modo. Quale sarebbe il modo corretto di progettare questo tipo per farla franca con un solo livello di generici?


Minimal reproducible example on Rust playpen

Per riferimento, la mia versione del compilatore è:

$ rustc --version 
rustc 1.1.0-dev (built 2015-04-26) 

risposta

7

Da quanto ho capito, il tuo codice originale è parametrizzata su T, ma avete metodi che vogliono specificare il parametro . Il trucco è non avere un generico per questi casi. Prova invece a creare implementazioni specializzate per ogni tipo interessante:

// this is just an example. suppress unrelated warnings 
#![allow(dead_code, unused_variables)] 

struct Foobar<T> { 
    origin: T, 
} 

trait Orange {} 

struct Grapefruit; 

impl Orange for Grapefruit {} 

impl Foobar<()> { 
    fn from_nowhere() -> Foobar<()> { 
     Foobar { origin:() } 
    } 
} 

impl<'a, F> Foobar<&'a mut F> 
    where F: Orange 
{ 
    fn from_orange(orange: &'a mut F) -> Foobar<&'a mut F> { 
     Foobar { origin: orange } 
    } 
} 

impl<F> Foobar<F> 
    where F: FnMut(u64) -> u64 
{ 
    fn from_callback(callback: F) -> Foobar<F> { 
     Foobar { origin: callback } 
    } 
} 

fn main() { 
    let mut fruit = Grapefruit; 

    // What I actually wanted to do 
    let a1 = Foobar::from_nowhere(); 
    let b1 = Foobar::from_orange(&mut fruit); 
    let c1 = Foobar::from_callback(|x| x*x); 
} 
+1

Grazie! Ciò di cui non mi rendevo conto era che è possibile avere più clausole "impl" per diverse parametrizzazioni. –