2015-05-03 19 views
5

Tôi đang viết một liên kết Rust cho thư viện C. Nó thực hiện một thực thể có thể được xây dựng từ các thực thể nguồn khác nhau, có thể tiết kiệm một số tham chiếu bên trong. Tôi muốn loại Rust thực thi chính sách quyền sở hữu an toàn, do đó cấu trúc bao bọc là chung chung, được tham số hóa theo loại tham chiếu được lưu trữ.Chú thích kiểu rõ ràng cho hàm tạo chung của kiểu chung

struct Foobar<T> { 
    origin: T, 
} 

Sau đó, tôi triển khai một số hàm tạo cho loại Foobar của mình.

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

Và ở đây có vấn đề: cả cấu trúc và hàm tạo được tham số độc lập. Trong khi tham số kiểu constructor có thể được suy ra từ các đối số của nó, tham số kiểu struct không được sử dụng trong hàm tạo và không thể suy ra. Do đó, cách ngây thơ để gọi một constructor

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

confuses 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(); 

Nó có thể được cố định bằng cách cung cấp một số tham số kiểu bất kỳ:

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

... đó là tất cả loại xấu xí. Một cách khác để giải quyết vấn đề sẽ là biến các nhà xây dựng thành các hàm miễn phí, mặc dù nó sẽ là (kinda) không thành ngữ.

Câu hỏi đặt ra là, tôi có thiếu gì đó không? Thiết kế dường như thiếu sót theo một cách nào đó. Điều gì sẽ là cách thích hợp để thiết kế loại này để có được chỉ với một mức độ generics?


Minimal reproducible example on Rust playpen

Để tham khảo, phiên bản trình biên dịch của tôi là:

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

Trả lời

7

Theo tôi được biết, mã ban đầu của bạn là tham số trên T, nhưng bạn có phương pháp mà muốn xác định các tham số . Bí quyết là không có số chung cho những trường hợp này. Thay vào đó, hãy thử tạo các triển khai chuyên biệt cho từng loại thú vị:

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

Cảm ơn bạn! Những gì tôi đã không nhận ra là nó có thể có nhiều mệnh đề 'impl' cho các tham số khác nhau. –

Các vấn đề liên quan