Array cannot be indexed by RangeFull?

家住魔仙堡 提交于 2021-01-29 03:45:56

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!