问题 索引操作的返回类型是什么?


我正在努力,非常不成功地玩切片。

我把我的第一个问题减少到:

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

我的期望是返回类型 slice[index] 作为参考,鉴于 文件

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

但是,编译器给我一个错误:

error[E0308]: mismatched types
 --> src/main.rs:3:5
  |
3 |     item
  |     ^^^^ expected reference, found type parameter
  |
  = note: expected type `&'a T`
             found type `T`

我将其解释为含义类型 item 与函数的返回类型不匹配(我介绍过 item 仅用于调试目的,从返回中拆分表达式评估)。

如果我将返回类型切换为 T,这是类型 item,我收到另一条错误消息:

error[E0508]: cannot move out of type `[T]`, a non-copy slice
 --> src/main.rs:2:16
  |
2 |     let item = slice[index];
  |                ^^^^^^^^^^^^
  |                |
  |                cannot move out of here
  |                help: consider using a reference instead: `&slice[index]`

经过修补,我找到了两个解决方法:

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
}

强制该类型作为参考就可以了。

为什么这些恶作剧首先是必要的? 难道我做错了什么?


10595
2018-01-10 17:40


起源



答案:


这是编译器为您做的一些有用的人体工程学设计,以使代码看起来更好一些。

的返回值 Index 特征  引用,但编译器会自动为您插入一个取消引用 当你使用含糖的语法  []。大多数其他语言只会从数组中返回该项(复制它或返回对该对象的另一个引用,无论什么是合适的)。

由于Rust的移动/复制语义的重要性,你不能总是复制一个值,所以在这些情况下,你通常会使用 &

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

请注意,索引值也会通过引用自动获取,类似于自动取消引用。


10
2018-01-10 17:51



啊!我明白了,所以我被糖的吸引了 []!我没想过打电话 index 直接因为我没想到会有所不同,即使我已经注意到调用的差异 [] 同 T 会不会打电话 index 同 &T。谢谢你的插图,它确实有助于形象化。 - Matthieu M.


答案:


这是编译器为您做的一些有用的人体工程学设计,以使代码看起来更好一些。

的返回值 Index 特征  引用,但编译器会自动为您插入一个取消引用 当你使用含糖的语法  []。大多数其他语言只会从数组中返回该项(复制它或返回对该对象的另一个引用,无论什么是合适的)。

由于Rust的移动/复制语义的重要性,你不能总是复制一个值,所以在这些情况下,你通常会使用 &

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

请注意,索引值也会通过引用自动获取,类似于自动取消引用。


10
2018-01-10 17:51



啊!我明白了,所以我被糖的吸引了 []!我没想过打电话 index 直接因为我没想到会有所不同,即使我已经注意到调用的差异 [] 同 T 会不会打电话 index 同 &T。谢谢你的插图,它确实有助于形象化。 - Matthieu M.


不,你正在做的一切正确。而 index() 方法确实返回一个引用,当在索引操作中调用它时,它的结果会自动解除引用。这样做是为了使索引更自然:在存在某种索引操作符的每种语言(主要是C和C ++)中,它返回值本身,而不是对容器的引用。

为了获得对集合的引用,您必须明确地应用引用运算符(如在第一个“变通方法”中)或使用引用模式(如第二个)。


6
2018-01-10 17:46