我开始使用类似这样的函数(playground):
fn find <T: Copy> (src: &[T], index: usize) -> T {
// more complex algorithm, involving src goes here
src[index]
}
pub fn main() {
let x = b"abc";
assert_eq!(b'b', find(x, 1));
}
我想概括它,以便我可以为src
使用任何合适的类型。我想出的最好的是(playground):
trait RandomAccess<T> {
fn get_at(&self, index: usize) -> T;
}
impl <T: Copy> RandomAccess<T> for [T] {
fn get_at(&self, index: usize) -> T {
self[index]
}
}
fn find <T: Copy, S: ?Sized + RandomAccess<T>> (src: &S, index: usize) -> T {
// more complex algorithm, involving src goes here
src.get_at(index)
}
pub fn main() {
let x = b"xyz";
assert_eq!(b'y', find(&x[..], 1));
}
但是,我现在不能只调用find(x, 1)
,我必须创建一个切片:find(&x[..], 1)
。
有没有办法让这个通用,但仍然可以像原始示例一样调用find
?
答案 0 :(得分:2)
由于生锈编译器(https://github.com/rust-lang/rust/issues/29504)的限制,您的第二个示例目前无法正常工作。但是,有几种方法可以解决这个问题。
最简单的方法是为所有RandomAccess<T>
实施C: AsRef<[T]>
。这样,它就可以与[T; n]
,&[T]
,Vec<T>
等一起使用:
trait RandomAccess<T> {
fn get_at(&self, index: usize) -> T;
}
impl<T: Copy, C: AsRef<[T]>> RandomAccess<T> for C {
fn get_at(&self, index: usize) -> T {
self.as_ref()[index]
}
}
fn find<T: Copy, C: RandomAccess<T>>(src: C, index: usize) -> T {
src.get_at(index)
}
不幸的是,如果您这样做,您将无法添加任何其他RandomAccess
impl,因此您可以更改find
以使某些集合满足AsRef<[T]>
:
fn find<T: Copy, C: AsRef<[T]>> (src: C, index: usize) -> T {
src.get_at(index)
}
或者,如果您需要能够支持无法借用[T]
的集合,则可以为RandomAccess<T>
实施[T; n]
对于使用宏的某个范围内的所有n
:
trait RandomAccess<T> {
fn get_at(&self, index: usize) -> T;
}
impl<T: Copy> RandomAccess<T> for [T] {
fn get_at(&self, index: usize) -> T {
self[index]
}
}
macro_rules! impl_random_access {
($($n:expr,)*) => {
$(
impl <T: Copy> RandomAccess<T> for [T; $n] {
fn get_at(&self, index: usize) -> T {
self[index]
}
}
)*
}
}
impl_random_access! {
01,02,03,04,05,06,07,08,
09,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,
25,26,27,28,29,30,31,32,
}
fn find<T: Copy, S: ?Sized + RandomAccess<T>>(src: &S, index: usize) -> T {
src.get_at(index)
}
当我们最终获得类型级常量(当前在愿望清单上)时,您应该能够为所有RandomAccess<T>
实施[T; n]
。但就目前而言,您需要使用宏。