这是一个特点(简化的问题)我想实现的每一个行为像一个片类型的:
trait SliceLike {
type Item;
/// Computes and returns (owned) the first item in a collection.
fn first_item(&self) -> Self::Item;
}
注意,Item
类型是相关联的类型;我想每一个类型,它是SliceLike
有一个独特的元素类型。
这里是在一条毯子实现尝试:
use std::ops::Deref;
impl<T: Clone, U: Deref<Target = [T]>> SliceLike for U {
type Item = T;
fn first_item(&self) -> Self::Item {
self[0].clone()
}
}
例如,该编译和运行:
let data: Vec<usize> = vec![3, 4];
assert_eq!(data.first_item(), 3);
let data: &[usize] = &[3, 4];
assert_eq!(data.first_item(), 3);
let data: Box<[usize]> = Box::new([3, 4]);
assert_eq!(data.first_item(), 3);
let data: Rc<[usize]> = Rc::new([3, 4]);
assert_eq!((&data).first_item(), 3);
这也编译和运行:
fn stub(x: &[usize]) -> usize {
x.first_item()
}
let data: [usize; 2] = [3, 4];
assert_eq!(stub(&data), 3);
assert_eq!(stub(&[3, 4]), 3);
但是,如果我直列stub()
它未能编译:
let data: [usize; 2] = [3, 4];
assert_eq!(data.first_item(), 3); // Fails.
assert_eq!([3, 4].first_item(), 3); // Fails.
毯子实现使用编译器本身使用转向其他类型的成片的Deref
特质。这将捕获所有第三方的类型也表现得像一个切片。
该错误消息是:
error[E0599]: no method named `first_item` found for type `[usize; 2]` in the current scope
--> src/lib.rs:20:21
|
20 | assert_eq!(data.first_item(), 3); // Fails.
| ^^^^^^^^^^
|
= note: the method `first_item` exists but the following trait bounds were not satisfied:
`[usize; 2] : SliceLike`
`[usize] : SliceLike`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `first_item`, perhaps you need to implement it:
candidate #1: `SliceLike`
在这个问题上的take 1,有人建议我使用AsRef
代替Deref
的。该解决方案将不会在这里工作,因为有些类型可能实现一个以上的元素类型AsRef
。
我想我明白是怎么回事。对于每种类型T
有一个独特的类型<T as Deref>::Target
。当T
是&[usize; 2]
目标是[usize; 2]
,不[usize]
。编译器能够强制&[T; 2]
到&[T]
如果我明确的告诉它来,例如通过使用let
或stub()
,但如果我不这么做,这并不能够制定出胁迫是必需的。
但是,这是令人沮丧:这是完全显然对人类有什么失败调用打算这样做,编译器理解什么是需要Vec<usize>
,Box<[usize]>
,Rc<[usize]>
,&[usize]
等等,所以它似乎没有不合理的尝试,使其工作对于[usize; 2]
为好。
有没有写first()
这样最后两个电话工作太方便的方法是什么?如果没有,是否有一个语法要求编译器强迫一个&[usize; 2]
到&[usize]
内联,即不使用let
或stub()
?
Deref
为Vec
,Box
,Rc
,&T where T: ?Sized
实施并没有对数组([T; N]
)的实现,这就是为什么[3, 4].first_item()
不起作用。
这是不可能实现用于由于Deref
[T; N]
coherence rules,因此,阵列必须被强制转换为切片这种或那种方式。我所知道的最好的方法如下:
let data: [usize; 2] = [3, 4];
assert_eq!((&data[..]).first_item(), 3); // Ok
请注意,这类问题可能会消失,一旦const generic合并。