gpt4 book ai didi

rust - 使用 impl Trait 时如何获得 Deref 强制转换(第 2 课)

转载 作者:行者123 更新时间:2023-11-29 08:07:15 25 4
gpt4 key购买 nike

这是我想为每个行为类似于切片的类型实现的特征(针对问题进行了简化):

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]如果我明确要求它,例如通过使用 letstub() ,但如果我不这样做,那么就无法确定需要强制转换。

但这令人沮丧:对于人类来说,失败调用的目的是显而易见的,编译器理解 Vec<usize> 需要什么。 , Box<[usize]> , Rc<[usize]> , &[usize]依此类推,因此尝试使其适用于 [usize; 2] 似乎并不合理

有没有方便的写法first()这样最后两个电话也可以吗?如果不是,是否有语法要求编译器强制执行 &[usize; 2]&[usize]内联, 不使用 letstub()

Playground

最佳答案

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合并。

关于rust - 使用 impl Trait 时如何获得 Deref 强制转换(第 2 课),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54451342/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com