我如何推广一个接受`& [T]`的函数,这样我仍然可以用bytestring文字调用它?

时间:2016-09-21 18:37:24

标签: rust slice traits

我开始使用类似这样的函数(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

1 个答案:

答案 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]。但就目前而言,您需要使用宏。