rust - 使用 impl Trait 时如何获得 Deref 强制

标签 rust traits coercion

此函数返回类列表集合的第一个元素。它适用于各种不同的类似列表的类型:

fn first<T: Copy>(x: impl Deref<Target=[T]>) -> T {
    x[0]
}

例如,编译并运行:

let data: Vec<usize> = vec![3, 4];
assert_eq!(first(data), 3);

let data: &[usize] = &[3, 4];
assert_eq!(first(data), 3);

let data: Rc<[usize]> = Rc::new([3, 4]);
assert_eq!(first(data), 3);

这也编译并运行:

fn stub(x: &[usize]) -> usize {
    first(x)
}

let data: &[usize; 2] = &[3, 4];
assert_eq!(stub(data), 3);

assert_eq!(stub(&[3, 4]), 3);

但是编译失败:

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

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

错误信息是:

type mismatch resolving `<&[usize; 2] as std::ops::Deref>::Target == [_]`

我想我明白发生了什么。对于每种类型 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 .

最佳答案

您想使用 AsRef , 而不是 Deref:

use std::rc::Rc;

fn first<T: Copy>(x: impl AsRef<[T]>) -> T {
    x.as_ref()[0]
}

fn main() {
    let data: Vec<usize> = vec![3, 4];
    assert_eq!(first(data), 3);

    let data: &[usize] = &[3, 4];
    assert_eq!(first(data), 3);

    let data: Rc<[usize]> = Rc::new([3, 4]);
    assert_eq!(first(data), 3);

    let data: &[usize; 2] = &[3, 4];
    assert_eq!(first(data), 3);
}

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

相关文章:

JavaScript 对象 : Using Arguments as object property

closures - 为闭包类型别名实现特征

rust - 首先获取迭代器的所有内容。在使用rust

generics - 为实现特征的所有类型实现特征

php - 如何在 php-class 中使用 traits?

javascript - 为什么 JavaScript 会有这样的行为?

haskell - 为什么不能在 GHC 中强制超功能?

rust - 如何合并流的迭代器?

rust - 如果我在代码的各个位置使用了非可变变量,为什么会出现借来的错误?

rust - 如何编写区分有符号和无符号 int 的通用函数?