rust - 使用 impl Trait 时如何获得 Deref 强制(取 2)
问题描述
这是我想为每个表现得像切片的类型实现的特征(为问题简化):
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`
在这个问题的第 1个问题中,我被建议使用AsRef
而不是Deref
. 该解决方案在这里不起作用,因为某些类型可能实现AsRef
不止一种元素类型。
我想我明白发生了什么。每种类型T
都有一个唯一的类型<T as Deref>::Target
。什么时候T
是&[usize; 2]
目标[usize; 2]
,不是[usize]
。如果我明确要求,编译器可以强制&[T; 2]
执行&[T]
,例如使用let
or stub()
,但如果我不这样做,则无法确定强制执行是必需的。
但这令人沮丧:对于人类来说,失败的调用意图做什么是完全显而易见的,并且编译器了解Vec<usize>
, Box<[usize]>
,等需要什么Rc<[usize]>
,&[usize]
因此尝试使其也适用似乎并非不合理[usize; 2]
。
有没有一种方便的编写方法,first()
以便最后两个调用也可以工作?如果没有,是否有语法要求编译器将 a 强制&[usize; 2]
为&[usize]
内联,即不使用let
or stub()
?
解决方案
Deref
为 , , 实现了Vec
,Box
并且Rc
没有&T where T: ?Sized
数组 ( [T; N]
) 的实现,这就是为什么[3, 4].first_item()
不起作用。
由于连贯性规则,无法实现Deref
for ,因此,必须以一种或另一种方式将数组强制转换为切片。我知道的最好的方法如下:[T; N]
let data: [usize; 2] = [3, 4];
assert_eq!((&data[..]).first_item(), 3); // Ok
请注意,一旦const generic被合并,这样的问题可能会消失。
推荐阅读
- git - Git添加不起作用,推送已删除的文件
- google-maps - WebGL Overlay 谷歌地图:如何投射阴影?
- reactjs - Reactjs 单元测试:如何覆盖 useEffect 钩子中的代码?使用 Jest 和 Enzyme
- recaptcha - Recptcha V3 与原型版本冲突:'1.7' 问题
- javascript - Javascript - 文档查询选择器
- python - 如何在流式传输期间每 n 秒获取特定帧?
- php - 作曲家需要没有命令
- java - 尝试在 Eclipse 中构建 Gradle 项目时出错
- javascript - 使用循环向 Mapbox 地理编码添加多个点
- javascript - 我正在编写函数来查看学院的详细信息,它显示了该学院的专业数量。如何在模板中计算数组?