2017-02-08 14 views
6

Tôi có một đặc điểm mà tôi muốn cung cấp một phương pháp. Phương pháp này sẽ được thực hiện theo một số người trợ giúp không có doanh nghiệp nào bên trong đặc điểm và không đủ tầm thường để đa hình năng động có ý nghĩa hơn là làm cho chúng trở nên chung chung. Vì vậy, tôi có mã dọc theo dòng củaPhương thức đúc & tự đối tượng được cung cấp

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self); 
    } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

nào, tuy nhiên, does not compile, với lỗi:

error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied 
--> <anon>:9:19 
    | 
9 |   use_trait(self); 
    |     ^^^^ the trait `std::marker::Sized` is not implemented for `Self` 
    | 
    = help: consider adding a `where Self: std::marker::Sized` bound 
    = note: required for the cast to the object type `Trait` 

Tôi hiểu tại sao-nó không được bảo đảm ai đó sẽ không thực hiện các đặc điểm cho một loại không đúng cở (chuyển đổi từ &T where T: Trait thành &Trait yêu cầu T: Sized, nhưng việc khai báo không yêu cầu điều đó).

Tuy nhiên, lời khuyên sẽ không làm những gì tôi cần. Tôi có thể thêm

fn needed(&self) -> &str where Self: Sized 

nhưng sau đó needed() phương pháp sẽ không có thể truy cập vào &Trait (vì Trait : ?Sized), trong đó ám chỉ rằng điều vô ích, bởi vì các loại (một trong những thực tế mà làm điều gì đó hữu ích) là luôn được xử lý là Arc<Trait>. Và thêm

trait Trait: Sized 

thậm chí còn tồi tệ hơn, bởi vì đó không cho phép &Trait ở tất cả (Trait như một loại là không đúng cở, vì vậy Trait loại không không thực hiện đặc điểm Trait).

Dĩ nhiên tôi chỉ đơn giản có thể làm cho

fn use_trait<T: Trait>(x: &T) 

nhưng có rất nhiều đằng sau đó trong các mã sản, vì vậy tôi không muốn monomorphisation có đặc biệt là kể từ khi đặc điểm là nếu không luôn luôn xử lý như đối tượng tính trạng.

Có cách nào để nói với Rust rằng tất cả các loại mà impl Trait phải có kích thước và đây là định nghĩa về một phương pháp sẽ hoạt động cho tất cả chúng?

+0

Xem thêm [đối tượng Trait đối tượng Rust Trait] (http://stackoverflow.com/q/41604107/155423) – Shepmaster

Trả lời

0

phiên bản cải tiến của @JoshuaEntrekin's answer:

Các helper as_trait chức năng có thể được đặt trong một đặc điểm phụ mà được thực hiện chăn cho tất cả Sized loại cố gắng để thực hiện Trait. Sau đó, người triển khai Trait không phải làm bất kỳ điều gì đặc biệt và chuyển đổi hoạt động.

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait : AsTrait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self : AsTrait { 
     use_trait(self.as_trait()); 
    } 
} 

trait AsTrait { 
    fn as_trait(&self) -> &Trait; 
} 

impl<T : Trait + Sized> AsTrait for T { 
    fn as_trait(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 
} 

fn main() { 
    Struct().provided(); 
} 

(trên play).

Cũng có thể chỉ cần đặt provided trong đặc điểm phụ, nhưng sau đó nó sẽ phải tự động gửi đến các phương thức khác Self không cần thiết.


Cập nhật: Thực tế, bạn vẫn có thể ghi đè provided.

Bây giờ, ở trên có thể được cải thiện hơn nữa bằng cách làm cho nó chung chung. Có std::makrer::Unsize, không ổn định tại thời điểm viết bài này. Chúng tôi không thể thực hiện

trait Trait : Unsize<Trait> 

vì Rust không cho phép CRTP, nhưng may mắn là đủ để đặt ràng buộc vào phương pháp. Vì vậy,

fn use_trait(x: &Trait) { 
    println!("object says {}", x.needed()); 
} 

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) where Self: AsObj<Trait> { 
     use_trait(self.as_obj()); 
    } 
} 

trait AsObj<Tr: ?Sized> { 
    fn as_obj(&self) -> &Trait; 
} 

// For &'a Type for Sized Type 
impl<Type: Trait> AsObj<Trait> for Type { 
    fn as_obj(&self) -> &Trait { self } 
} 

// For trait objects 
impl AsObj<Trait> for Trait { 
    fn as_obj(&self) -> &Trait { self } 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn provided(&self) { 
     println!("Aber dieses Objekt sagt Grüß Gott, Welt!"); // pardon my German, it is rusty. 
    } 
} 

fn main() { 
    let s: &Trait = &Struct(); 
    s.provided(); 
} 

(trên play)

này cuối cùng đã làm cho nó minh bạch cho người thực hiện của các phiên bản khác.

Xem thêm this users thread.

2

Bạn cần có thêm as_trait chức năng trên Trait và triển khai của nó:

trait Trait { 
    fn needed(&self) -> &str; 

    fn provided(&self) { 
     use_trait(self.as_trait()); 
    } 

    fn as_trait(&self) -> &Trait; 
} 

struct Struct(); 

impl Trait for Struct { 
    fn needed(&self) -> &str { 
     "Hello, world!" 
    } 

    fn as_trait(&self) -> &Trait { 
     self as &Trait 
    } 
} 

Bạn có thể thử nó trên sân chơi. (trait objects)

+0

"đối tượng tra cứu kiểu không xác định" có kích thước; hai 'usizes'. Một đặc điểm trần của chính nó, mà không có một đối tượng, là một loại chưa được đánh dấu. –

+0

Bạn có thể giải thích tại sao phương thức 'as_trait()' là cần thiết, và 'use_trait (self as & Trait)' không hoạt động trực tiếp trong 'provided()'? –

+0

@ChrisEmerson, tôi sẽ thêm giải thích cho câu hỏi đó. Nó là khá rõ ràng lý do tại sao nó không hoạt động một cách đơn giản. –

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