问题
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()?
Playground.
回答1:
You want to use AsRef, not 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);
}
来源:https://stackoverflow.com/questions/54400803/how-to-get-deref-coercion-when-using-impl-trait