2015-05-03 39 views
5

jenerik kurucusu için açık bir ek açıklama C kütüphanesi için bir Rust ciltleme yazıyorum. Farklı kaynak varlıklardan oluşturulabilecek, muhtemelen bazı referansları dahili olarak kaydedebilen bir varlık uygular. Pas türünün güvenli bir mülkiyet politikasını zorunlu kılmasını istiyorum. Bu nedenle, sarıcı yapı, saklı referansın türüne göre parametrelenmiş, geneldir. Genel tip

struct Foobar<T> { 
    origin: T, 
} 

Sonra benim Foobar türü için bazı oluşturucular uygulamak.

Ve işte problem geliyor: hem yapı hem de yapıcı bağımsız olarak parametreleniyor. Yapıcı tipi parametresi argümanlarından çıkarılabilirken, yapı tipi parametresi yapıcıda kullanılmaz ve çıkarım edilemez. Böylece, naif yolu, kurucuların

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

aramaya karıştırır 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(); 

Bazı keyfi türü parametresi sağlayarak düzeltilebilir:

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

... hepsi bu çirkin çeşitler. Sorunu çözmenin bir başka yolu, kurucuları serbest fonksiyonlara dönüştürmek olacaktır, ancak bu (kinda) ideolojik değildir.

Soru şu ki, bir şey mi eksik? Tasarım bir şekilde kusurlu gibi görünüyor. Sadece bir seviyedeki jenerikle kurtulmak için bu tipin tasarlanmasının uygun yolu ne olurdu? Başvuru için


Minimal reproducible example on Rust playpen

, benim derleyici sürümü:

Anladığım kadarıyla
$ rustc --version 
rustc 1.1.0-dev (built 2015-04-26) 

cevap

7

, orijinal kod T üzerinde parametreli, ancak parametresini belirtmek istediğiniz yöntemleri var . Hile, bu durumlar için genel bir olmamalıdır. Bunun yerine, her bir ilginç tür için özel uygulamalar oluşturmayı deneyin:

// 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

Teşekkür ederiz! Fark etmediğim şey, farklı parametreler için çoklu 'impl' cümlelerinin olması olabilirdi. –