使用 impl Trait 时如何获得 Deref 强制(采取 2) [英] How to get Deref coercion when using impl Trait (take 2)

查看:20
本文介绍了使用 impl Trait 时如何获得 Deref 强制(采取 2)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个特征(针对问题进行了简化),我想为每个表现得像切片的类型实现它:

Here is a trait (simplified for the question) which I'd like to implement for every type that behaves like a slice:

trait SliceLike {
    type Item;

    /// Computes and returns (owned) the first item in a collection.
    fn first_item(&self) -> Self::Item;
}

注意Item类型是关联类型;我希望 SliceLike 的每种类型都具有唯一的元素类型.

Note that the Item type is an associated type; I want each type that is SliceLike to have a unique element type.

这是一个全面实施的尝试:

Here is an attempt at a blanket implementation:

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()
    }
}

例如,这将编译并运行:

For example, this compiles and runs:

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() 它无法编译:

But if I inline stub() it fails to compile:

let data: [usize; 2] = [3, 4];
assert_eq!(data.first_item(), 3); // Fails.

assert_eq!([3, 4].first_item(), 3); // Fails.

整体实现使用 Deref 特性,编译器本身使用该特性将其他类型转换为切片.它将捕获所有行为也像切片的第三方类型.

The blanket implementation uses the Deref trait that the compiler itself uses to turn other types into slices. It will catch all third-party types that also behave like a slice.

错误信息是:

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.

In take 1 of this question, I was advised to use AsRef instead of Deref. That solution won't work here, because some type might implement AsRef for more than one element type.

我想我明白发生了什么.对于每种类型T,都有一个唯一的类型::Target.当 T&[usize;2] 目标是[usize;2],而不是 [usize].编译器能够强制 &[T;2]&[T] 如果我明确要求它,例如通过使用 letstub(),但如果我不这样做,则无法确定需要强制转换.

I think I understand what is going on. For each type T there is a unique type <T as Deref>::Target. When T is &[usize; 2] the target is [usize; 2], not [usize]. The compiler is able to coerce &[T; 2] to &[T] if I explicitly ask it to, e.g. by using let or stub(), but if I don't then it's not able to work out that the coercion is required.

但它令人沮丧:对于人类来说失败的调用打算做什么是非常明显的,并且编译器理解VecBox<[usize]>的要求;, Rc<[usize]>, &[usize] 等等,所以尝试让它工作似乎不是不合理的对于 [usize;2] 也是.

But it's frustrating: it's perfectly obvious to a human what the failing calls are intended to do, and the compiler understands what's required for Vec<usize>, Box<[usize]>, Rc<[usize]>, &[usize] and so on, so it doesn't seem unreasonable to try to make it work for [usize; 2] as well.

是否有一种方便的方法来编写 first() 以便最后两个调用也能工作?如果没有,是否有语法要求编译器强制一个 &[usize;2]&[usize] 内联,ie 不使用 letstub()>?

Is there a convenient way to write first() so that the last two calls work too? If not, is there a syntax to ask the compiler to coerce a &[usize; 2] to a &[usize] inline, i.e. without using let or stub()?

游乐场

推荐答案

Deref 是为 Vec, Box, Rc, &T where T: ?Sized 并且没有t 数组的实现 ([T; N]),这就是 [3, 4].first_item() 不起作用的原因.

Deref is implemented for Vec, Box, Rc, &T where T: ?Sized and there isn't an implementation for arrays ([T; N]), that is why [3, 4].first_item() doesn't work.

不可能为 [T; 实现 DerefN] 由于一致性规则 因此,必须以某种方式将数组强制转换为切片.我所知道的最好的方法如下:

It isn't possible to implement Deref for [T; N] due to coherence rules, therefore, the array must be coerced to a slice one way or another. The best method I am aware of is as follows:

let data: [usize; 2] = [3, 4];
assert_eq!((&data[..]).first_item(), 3); // Ok

请注意,一旦 const generic 合并.

Please note that issues like this are probably going to disappear once const generic is merged.

这篇关于使用 impl Trait 时如何获得 Deref 强制(采取 2)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆