RangeFull无法索引数组?

问题描述 投票:1回答:1

请考虑以下示例:

use std::ops::Index;
use std::ops::RangeFull;

fn f<T: Index<RangeFull>>(x: T) {}

fn main() {
    let x: [i32; 4] = [0, 1, 2, 3];
    f(x);
}

在调用f(x)时,我收到一个错误:

error[E0277]: the type `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
 --> src/main.rs:8:5
  |
8 |     f(x);
  |     ^ `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
  |
  = help: the trait `std::ops::Index<std::ops::RangeFull>` is not implemented for `[i32; 4]`
note: required by `f`
 --> src/main.rs:4:1
  |
4 | fn f<T: Index<RangeFull>>(x: T) {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我很迷惑。我可以写一下,例如,let y = x[..];。这不意味着用x索引RangeFull吗?数组在这方面有点特别吗?

rust traits
1个回答
2
投票

正如你在documentation for the primitive array type中看到的那样,Index<…>并不直接用于数组。这部分是因为目前不可能为所有阵列大小提供全面实现,但主要是因为它没有必要;对于大多数目的,切片的实现已足够。

表达式x[..]由编译器转换为*std::ops::Index::index(&x, ..),而编译器又根据usual method call semantics进行评估。由于没有为数组实现Index<RangeFull>,编译器反复取消引用&x并在最后执行unsized强制,最终找到Index<RangeFull>[i32]的实现。

调用泛型函数的过程(如示例中的f())与方法调用语义不同。编译器首先根据您传递的参数推断T是什么;在这种情况下,T被推断为[i32; 4]。在下一步中,编译器会验证T是否满足特征边界,并且由于它没有,因此会收到错误消息。

如果我们想让你的代码工作,我们需要确保将切片传递给f()。由于切片是未定义的,我们需要通过引用传递它,因此我们需要像这样定义f()

fn f<T: ?Sized + Index<RangeFull>>(_: &T) {}

?Sized是必要的,因为类型参数接收隐含的Sized界限。在调用f()时,我们需要确保T实际上被推断为[i32]而不是[i32; 4]。为此,我们可以明确指定T

f::<[_]>(&x);

或者在传递参数之前显式执行unsized转换,因此编译器会推断出所需的类型:

f(&x as &[_]);
f(&x[..])
© www.soinside.com 2019 - 2024. All rights reserved.