Rust 如何在使用impl Trait时获得Deref强制(第2步)
下面是一个特性(针对问题进行了简化),我想为每种行为类似于切片的类型实现它:Rust 如何在使用impl Trait时获得Deref强制(第2步),rust,traits,coercion,Rust,Traits,Coercion,下面是一个特性(针对问题进行了简化),我想为每种行为类似于切片的类型实现它: trait SliceLike { type Item; /// Computes and returns (owned) the first item in a collection. fn first_item(&self) -> Self::Item; } 请注意,项类型是关联类型;我希望SliceLike的每个类型都有一个唯一的元素类型 下面是一个全面实施的尝试: us
trait SliceLike {
type Item;
/// Computes and returns (owned) the first item in a collection.
fn first_item(&self) -> Self::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()
}
}
但是如果我内联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]:在当前作用域中找不到类型“[usize;2]”名为“first\u item”的方法
-->src/lib.rs:20:21
|
20 |断言| eq!(data.first_item(),3);//失败。
| ^^^^^^^^^^
|
=注意:方法“first_item”存在,但不满足以下特征界限:
`[用法;2]:像`
`[用法]:像`
=帮助:只有在trait已实现且在范围内时,才能使用trait中的项
=注意:以下特征定义了一个项“first\u item”,可能您需要实现它:
候选人#1:`像切片机一样`
在这个问题中,有人建议我使用AsRef
而不是Deref
。该解决方案在这里不起作用,因为某些类型可能对多个元素类型实现AsRef
我想我明白发生了什么。对于每个类型T
都有一个唯一的类型::Target
。当T
是&[usize;2]
时,目标是[usize;2]
,而不是[usize]
。如果我明确要求编译器将&[T;2]
强制为&[T]
,例如使用let
或stub()
,编译器可以强制为&[T]
,但如果我不这样做,则无法确定强制是必需的
但它令人沮丧:对于人类来说,失败调用的意图是什么是显而易见的,而且编译器理解Vec
、Box
、Rc
、&[usize]
等等所需的内容,因此尝试让它也为[usize;2]
工作似乎并不不合理
是否有一种方便的方法来编写first()
,以便最后两个调用也能工作?如果没有,是否有语法要求编译器将&[usize;2]
强制为&[usize]
内联,即不使用let
或存根()
Deref
是为、实现的,而数组([t;N]
)没有实现,这就是为什么[3,4]。第一项()不起作用
无法为[t;N]
实现Deref
,因为必须以某种方式将数组强制为片。我所知道的最佳方法如下:
let data: [usize; 2] = [3, 4];
assert_eq!((&data[..]).first_item(), 3); // Ok
请注意,这样的问题可能会在合并后消失。impl-SliceLike for[T]
有什么问题吗?它当然满足一些要求。它允许您在许多有趣的类型上调用SliceLike
方法。然而,它不会满足诸如Vec:SliceLike
之类的特征边界,因此它会使编写在SliceLike
类型上多态的代码变得更加困难。我认为不可能同时拥有你的建议impl和我的建议impl,因为理论上可能[T]会在未来某个日期实施Deref。“由于连贯性规则,[T;N]
,[3,4],不可能对[T;N]
实施,而且更容易阅读。我想没关系。
let data: [usize; 2] = [3, 4];
assert_eq!(data.first_item(), 3); // Fails.
assert_eq!([3, 4].first_item(), 3); // Fails.
let data: [usize; 2] = [3, 4];
assert_eq!((&data[..]).first_item(), 3); // Ok