This function returns the first element of a list-like collection. It works for a variety of different list-like types:
fn first<T: Copy>(x: impl Deref<Target=[T]>) -> T {
x[0]
}
For example, this compiles and runs:
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);
This also compiles and runs:
fn stub(x: &[usize]) -> usize {
first(x)
}
let data: &[usize; 2] = &[3, 4];
assert_eq!(stub(data), 3);
assert_eq!(stub(&[3, 4]), 3);
But this fails to compile:
let data: &[usize; 2] = &[3, 4];
assert_eq!(first(data), 3); // Fails.
assert_eq!(first(&[3, 4]), 3); // Fails.
The error message is:
type mismatch resolving `<&[usize; 2] as std::ops::Deref>::Target == [_]`
I think I understand what is going on. For each type T
there is a unique type <T as Deref>::Target
. When T
is &[usize; 2]
the target is [usize; 2]
, not [usize]
. The compiler is able to coerce &[T; 2]
to &[T]
if I explicitly ask it to, e.g. by using let
or stub()
, but if I don't then it's not able to work out that the coercion is required.
But it's frustrating. It's perfectly obvious to a human what the failing calls are intended to do, and the compiler understands what's required for Vec<usize>
, Box<[usize]>
, Rc<[usize]>
, &[usize]
and so on, so it doesn't seem unreasonable to try to make it work for [usize; 2]
as well.
Question: Is there a convenient way to write first()
so that the last two calls work too? If not, is there a syntax to ask the compiler to coerce a &[usize; 2]
to a &[usize]
inline, i.e. without using let
or stub()
?
You want to use
AsRef
, notDeref
: