使用 impl Trait 时如何获得 Deref 强制
How to get Deref coercion when using impl Trait
此函数returns 类列表集合的第一个元素。它适用于各种不同的类似列表的类型:
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);
}
此函数returns 类列表集合的第一个元素。它适用于各种不同的类似列表的类型:
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);
}