如何使用IMPL特质时获得DEREF胁迫(坐2)

问题描述 投票:2回答:1

这是一个特点(简化的问题)我想实现的每一个行为像一个片类型的:

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

rust traits coercion
1个回答
2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.