2014-12-03 13 views
8

Mẫu có đặc điểm an toàn đối tượng Foo và đặc điểm mở rộng (có thể không an toàn) FooExt được triển khai cho tất cả các trường hợp Foo dường như trở thành tiêu chuẩn ngay bây giờ.Làm việc xung quanh các hạn chế của các đặc điểm mở rộng

https://github.com/rust-lang/rfcs/pull/445

Đây là một vấn đề đối với tôi trong trường hợp Iterator<A>, như tôi có một thư viện đó sẽ ghi đè phương pháp mặc định IteratorExt#last() của đặc điểm iterator cũ (thư viện nằm bên dưới có một thực hiện có hiệu quả last()). Điều này bây giờ là không thể, bởi vì đối với bất kỳ A, sẽ luôn có một triển khai đặc điểm xung đột của IteratorExt, số libcore đã cung cấp cho tất cả Iterator<A>.

iterator.rs:301:1: 306:2 error: conflicting implementations for trait `core::iter::IteratorExt` [E0119]

iterator.rs:301 impl<'a, K: Key> iter::IteratorExt<Vec<u8>> for ValueIterator<'a,K,Vec<u8>> { 
iterator.rs:302 fn last(&mut self) -> Option<Vec<u8>> { 
iterator.rs:303  self.seek_last(); 
iterator.rs:304  Some(self.value()) 
iterator.rs:305 } 
iterator.rs:306 } 
... 

Bây giờ, như xa như tôi thấy, tôi có hai lựa chọn:

  • có đặc điểm của riêng tôi và của riêng last() thực hiện của tôi. Điều đó có nghĩa là nó xung đột nếu IteratorExt được nhập trừ khi được sử dụng cẩn thận. Điều này cũng có nguy cơ vô tình sử dụng một phiên bản không hiệu quả của last() nếu phiên bản từ IteratorExt được sử dụng. Tôi sẽ mất quyền truy cập thuận tiện vào IteratorExt.
  • có đặc điểm riêng của tôi và đặt tên cho phương thức khác (seek_last()). Nhược điểm: Tôi yêu cầu người dùng học từ vựng và luôn ưu tiên phương pháp của tôi so với phương pháp được cung cấp bởi IteratorExt. Cùng một vấn đề: Tôi muốn tránh tình cờ sử dụng số last().

Có giải pháp nào khác, tốt hơn, tôi bị thiếu không?

Trả lời

2

Kể từ rustc 0.13.0-nightly (8bca470c5 2014-12-08 00:12:30 +0000) xác định last() làm phương pháp vốn có trên loại của bạn nên hoạt động.

#[deriving(Copy)] 
struct Foo<T> {t: T} 

impl<T> Iterator<T> for Foo<T> { 
    fn next(&mut self) -> Option<T> { None } 
} 

// this does not work 
// error: conflicting implementations for trait `core::iter::IteratorExt` [E0119] 
// impl<T> IteratorExt<T> for Foo<T> { 
// fn last(mut self) -> Option<T> { None } 
//} 

// but this currently does 
impl<T> Foo<T> { 
    fn last(mut self) -> Option<T> { Some(self.t) } 
} 


fn main() { 
    let mut t = Foo{ t: 3u }; 
    println!("{}", t.next()) 
    println!("{}", t.last()) // last has been "shadowed" by our impl 
    println!("{}", t.nth(3)) // other IteratorExt methods are still available 
} 

Vì bạn đang không được phép sử dụng những đặc điểm mở rộng như giới hạn chung (nhưng chỉ để cung cấp các phương pháp bổ sung), điều này về mặt lý thuyết nên làm việc cho kịch bản của bạn, như bạn có thể có kiểu riêng của bạn và impl của nó trong cùng một thùng.

Người dùng thuộc loại của bạn sẽ sử dụng phương pháp last vốn có thay vì phương thức IteratorExt nhưng vẫn có thể sử dụng các phương pháp khác trên IteratorExt.

+0

Tôi không thể làm việc này với 'rustc 0.13.0-night (193390d0e 2014-12-11 22:56:54 +0000)'. Không ghi đè phương thức, cảnh báo cho 'dead_code'. Tuy nhiên, tôi thích điều đó như một giải pháp. – Skade

+0

Cào rằng, tôi đã không làm cho phương pháp công khai để sử dụng nó trong thùng khác. Nó hoạt động với 'pub fn last (...)'. – Skade

+0

Điều này thường làm việc trong mã chung chung mà tiêu thụ một loại như vậy (với Iterator bị ràng buộc) và có thể sống trong một thùng? – sellibitze

0

last phải được di chuyển đến Iterator, thay vì IteratorExt.

IteratorExt là cần thiết khi sử dụng đối tượng Box<Iterator>, để cho phép gọi các phương thức chung chung trên chúng (ví dụ: map), bởi vì bạn không thể đặt phương thức chung trong vtable. Tuy nhiên, last không phải là chung chung, vì vậy nó có thể được đặt trong Iterator.

+0

Đây có thể là giải pháp cho vấn đề cụ thể này, nhưng câu hỏi đặt ra là hỏi về giải pháp chung cho các đặc điểm mở rộng. – Shepmaster

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