数组不能被RangeFull索引吗?

时间:2019-04-30 16:51:04

标签: rust traits

考虑以下示例:

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?数组在这方面有什么特殊之处吗?

1 个答案:

答案 0 :(得分:2)

如您在documentation for the primitive array type中所见,select r.* from (select r.*, lag(stateid) over (partition by idcont order by day_id) as prev_stateid, first_value(stateid) over (partition by idcont order by day_id desc) as last_stateid from reftable r ) r where stateid = last_stateid and (prev_stateid is null or prev_stateid <> stateid); 并非直接用于数组。部分原因是目前不可能为所有阵列大小提供统一的实现,但主要是因为没有必要。对于大多数用途而言,切片的实施就足够了。

表达式Index<…>由编译器翻译为x[..],编译器又根据usual method call semantics对其求值。由于没有针对数组的*std::ops::Index::index(&x, ..)的实现,因此编译器反复取消引用Index<RangeFull>并在最后执行不定大小的强制转换,最终为&x找到Index<RangeFull>的实现。 / p>

调用泛型函数(例如您的示例中的[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);