考虑以下示例:
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
吗?数组在这方面有什么特殊之处吗? 最佳答案
正如您在documentation for the primitive array type中看到的那样,Index<…>
没有直接为数组实现。部分原因是目前不可能为所有阵列大小提供一揽子实现,但主要是因为没有必要。切片的实现对于大多数目的而言已经足够。
编译器将x[..]
表达式转换为*std::ops::Index::index(&x, ..)
,然后根据usual method call semantics对其求值。由于没有针对数组的Index<RangeFull>
的实现,因此编译器反复取消引用&x
并在最后执行不定大小的强制转换,最终找到Index<RangeFull>
的[i32]
的实现。
调用泛型函数(例如您的示例中的f()
)的过程与方法调用语义不同。编译器首先根据您传递的参数推断出T
是什么。在这种情况下,T
推断为[i32; 4]
。在下一步中,编译器将验证T
是否满足特征范围,并且由于不满足,您将收到一条错误消息。
如果我们想使您的代码正常工作,则需要确保将一个切片传递给f()
。由于切片是未调整大小的,因此我们需要通过引用传递它,因此我们需要像这样定义f()
:
fn f<T: ?Sized + Index<RangeFull>>(_: &T) {}
?Sized
是必需的,因为类型参数接收隐式的Sized
绑定(bind)。在调用f()
时,我们需要确保T
实际上被推断为[i32]
而不是[i32; 4]
。为此,我们可以显式指定T
f::<[_]>(&x);
或在传递参数之前显式执行未调整大小的转换,因此编译器会推断出所需的类型:
f(&x as &[_]);
f(&x[..])
关于rust - 数组不能被RangeFull索引吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55925523/