此函数返回类似列表的集合的第一个元素。它适用于各种不同的类似列表的类型:
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]
强制转换为{em> ie 内联&[usize]
而不使用let
或stub()
?
答案 0 :(得分:1)
您要使用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);
}