2016-09-21 47 views
2

我開始了與一個功能有點像這樣(playground):如何推廣一個接受`&[T]`的函數,以便我仍然可以用字符串文字調用它?

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

似乎鏽編譯器在第一個例子中在幕後做了一些詭計,並且允許'&[u8; 3]'被強制爲'&[u8]',但在第二個例子中不能這樣做,因爲它不能肯定知道這是意圖。這基本上是問題嗎? –

+0

我試圖通過索引和其他一些東西來抽象化,但我並不確定你需要引入這樣的抽象 - 它們往往使事物複雜化而沒有增值。 find()'可以應用於其他'src'類型的是什麼? – ljedrz

+1

訣竅是:如果目標類型已知,強制觸發。由於'find'對'src'使用了一個類型參數,它不是。 – bluss

回答

2

由於鏽蝕編譯器(https://github.com/rust-lang/rust/issues/29504)的限制,第二個示例目前不工作。但是,有幾種解決方法。

最簡單的方法是對所有C: AsRef<[T]>實施RandomAccess<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 impls 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]。但現在,你需要使用宏。

+0

'AsRef'具有與[[T; 32]'。 – delnan

+1

你能解釋一下簡單版本('fn find (src:&[T])')的工作原理嗎?編譯器將'&[T; n]'強制轉換爲'&[T]'是否是一種特殊情況? –

+1

這是一個錯誤:https://github.com/rust-lang/rust/issues/29504。我已經更新了答案。 – Steven

相關問題