代码之家  ›  专栏  ›  技术社区  ›  apt1002

如何在使用impl Trait时获得Deref强制(第2步)

  •  2
  • apt1002  · 技术社区  · 7 年前

    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 德里夫 . 该解决方案在这里不起作用,因为某些类型可能会实现 AsRef

    我想我明白发生了什么。每种类型 T 有一种独特的类型 <T as Deref>::Target . 什么时候 T &[usize; 2] 目标是 [usize; 2] 不 [usize] . 编译器能够强制 &[T; 2] 到 &[T] 如果我明确要求,例如使用 let 或 ,但如果我不这样做,那么就无法确定是否需要强制。

    但这是令人沮丧的:对于一个人来说,失败调用的意图是什么是显而易见的,并且编译器知道需要做什么 Vec<usize> , Box<[usize]> , Rc<[usize]> , &[usize] [使用;2]

    有没有方便的写作方法 first() 所以最后两个电话也能用?如果没有,是否有语法要求编译器强制 & 到 &[使用] 内联, 不用 或 存根() ?

    Playground

    1 回复  |  直到 7 年前
        1
  •  2
  •   Caio    7 年前

    Deref 是为 Vec , Box Rc &T where T: ?Sized [T; N] ),这就是原因 [3, 4].first_item() 不起作用。

    这是不可能实现的 德里夫 对于 [T;N] 由于 coherence rules 因此,必须以某种方式将数组强制为切片。我所知道的最佳方法如下:

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

    请注意,像这样的问题可能会消失一次 const generic