问题
Consider the following example:
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);
}
Upon calling f(x)
, I get an error:
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) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I am confused. I can obviously write, for example, let y = x[..];
. Does this not mean indexing x
with RangeFull
? Are arrays somehow special in this regard?
回答1:
As you can see in the documentation for the primitive array type, Index<…>
is not directly implemented for arrays. This is partly because it would currently be impossible to provide blanket implementations for all array sizes, but mainly because it's not necessary; the implementation for slices is sufficient for most purposes.
The expression x[..]
is translated to *std::ops::Index::index(&x, ..)
by the compiler, which in turn is evaluated according to the usual method call semantics. Since there is no implementation of Index<RangeFull>
for arrays, the compiler repeatedly dereferences &x
and performs an unsized coercion at the end, eventually finding the implementation of Index<RangeFull>
for [i32]
.
The process of calling a generic function, like f()
in your example, is different from method call semantics. The compiler first infers what T
is based on the argument you are passing; in this case T
is inferred to be [i32; 4]
. In the next step, the compiler verifies whether T
satisfies the trait bounds, and since it doesn't, you get an error message.
If we want to make your code work, we need to make sure to pass a slice to f()
. Since a slice is unsized, we need to pass it by reference, so we need to define f()
like this:
fn f<T: ?Sized + Index<RangeFull>>(_: &T) {}
The ?Sized
is necessary since type parameters receive an implicit Sized
bound. When calling f()
, we need to make sure T
is actually inferred as [i32]
rather than [i32; 4]
. To this end, we can either explicitly specify T
f::<[_]>(&x);
or explicitly perform the unsized conversion before passing the argument, so the compiler infers the desired type:
f(&x as &[_]);
f(&x[..])
来源:https://stackoverflow.com/questions/55925523/array-cannot-be-indexed-by-rangefull