此函数返回类列表集合的第一个元素。它适用于各种不同的类似列表的类型:
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]
如果我明确要求它,例如通过使用 let
或 stub()
,但如果我不这样做,那么就无法确定需要强制转换。
但是这很令人沮丧。对于人类来说,失败调用的目的是显而易见的,并且编译器理解 Vec<usize>
需要什么。 , Box<[usize]>
, Rc<[usize]>
, &[usize]
依此类推,因此尝试使其适用于 [usize; 2]
似乎并不合理
问题:有没有方便的写法first()
这样最后两个电话也可以吗?如果不是,是否有语法要求编译器强制执行 &[usize; 2]
到 &[usize]
内联,即 不使用 let
或 stub()
?
最佳答案
您想使用 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/