2015-01-10 17 views
8

Tôi đang cố gắng, không thành công, để chơi xung quanh với lát.Loại trả về của hoạt động lập chỉ mục trên một lát là gì?

Tôi đã làm giảm số đầu tiên của tôi để:

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T { 
    let item = slice[index]; 
    item 
} 

Đó là mong đợi của tôi rằng kiểu trả về của slice[index] là một tài liệu tham khảo, do documentation:

pub trait Index<Index> { 
    type Output; 
    fn index(&'a self, index: &Index) -> &'a <Self as Index<Index>>::Output; 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
} 

Tuy nhiên, trình biên dịch mang lại cho tôi một lỗi:

error: mismatched types: expected &'a T , found T (expected &-ptr, found type parameter)

  item 
      ^~~~ 

Tôi giải thích là mea ning rằng loại item không khớp với kiểu trả về của hàm (tôi đã giới thiệu item chỉ dành cho mục đích gỡ lỗi, để phân tách đánh giá biểu thức từ trả về).

Và rõ ràng, nếu tôi chuyển loại trả về thành T là loại item tôi nhận được một thông báo lỗi khác về việc chuyển từ khoản vay như mong đợi.

Sau khi mày mò một chút, cuối cùng tôi có hai công việc ở quanh:

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T { 
    &slice[index] 
    ^
} 

fn at<'a, T>(slice: &'a [T], index: usize) -> &'a T { 
    let ref item = slice[index]; 
     ^~~ 
    item 
} 

buộc kiểu là một tài liệu tham khảo hiện các trick.

Nhưng tại sao những shenanigans đó lại cần thiết ngay từ đầu? Tôi có làm gì sai không?

Trả lời

8

Đây là một chút công thái học hữu ích mà trình biên dịch làm cho bạn để làm cho mã trông đẹp hơn một chút.

Giá trị trả về của Index đặc điểm một tham chiếu, nhưng trình biên dịch sẽ tự động chèn một dereference cho bạn khi bạn sử dụng cú pháp sugared[]. Hầu hết các ngôn ngữ khác sẽ chỉ trả về mục từ mảng (sao chép nó hoặc trả về một tham chiếu khác cho đối tượng, bất cứ điều gì là thích hợp).

Do tầm quan trọng của ngữ nghĩa di chuyển/sao chép Rust, bạn có thể không phải lúc nào tạo một bản sao một giá trị, vì vậy trong những trường hợp đó, bạn sẽ thường sử dụng một &:

let items = &[1u8, 2, 3, 4]; 

let a: u8 = items[0]; 
let a: u8 = *items.index(&0); // Equivalent of above 

let b: &u8 = &items[0]; 
let b: &u8 = &*items.index(&0); // Equivalent of above 

Lưu ý rằng giá trị chỉ mục là cũng tự động được thực hiện bằng cách tham chiếu, tương tự như dereference tự động.

+0

Ah! Tôi hiểu rồi, vì vậy tôi bị bắt bởi đường của '[]'!Tôi đã không nghĩ đến việc gọi 'index' trực tiếp vì tôi không mong đợi một sự khác biệt, mặc dù tôi đã nhận thấy sự khác biệt gọi' [] 'với' T' sẽ desugar gọi 'index' bằng' & T'. Cảm ơn bạn đã minh họa, nó thực sự giúp hình dung mọi thứ. –

5

Không, bạn đang làm mọi thứ chính xác. Trong khi phương thức index() trả về một tham chiếu, khi nó được gọi trong một hoạt động lập chỉ mục, kết quả của nó được tự động bỏ qua. Điều này được thực hiện để việc lập chỉ mục tự nhiên hơn: trong mọi ngôn ngữ mà một số toán tử lập chỉ mục tồn tại (chủ yếu là C và C++), nó tự trả về các giá trị chứ không phải các tham chiếu vào các thùng chứa.

Để lấy tham chiếu vào bộ sưu tập, bạn phải áp dụng toán tử tham chiếu một cách rõ ràng (như trong "giải pháp thay thế" đầu tiên của bạn) hoặc sử dụng mẫu tham chiếu (như trong phần thứ hai).

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