2016-09-21 10 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)です: find(&x[..], 1)

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を呼び出すことはできますか?

+0

最初の例の舞台裏でいくつかのトリッキーなことがあり、 '&[u8; 3]'を強制的に '&[u8]'にするようですが、2番目の例ではできませんこれが意図であることを確かめてください。それは基本的に問題ですか? –

+0

私はインデックスと他のものを抽象化しようとしましたが、私はあなたがそのような抽象概念を全く導入する必要がないことを確信しています - 付加価値なしで物事を複雑にする傾向があります。他の 'src'タイプ' find() 'はどのようなものに適用できますか? – ljedrz

+1

トリッキーなのは、宛先タイプがわかっている場合に強制的にトリガすることです。 'find'は' src'に型パラメータを使用しているので、そうではありません。 – bluss

答えて

2

あなたの2番目の例は、現在のところ錆びんコンパイラ(https://github.com/rust-lang/rust/issues/29504)の制限のために機能しません。しかし、これを回避する方法はいくつかあります。

最も簡単な方法は、すべてC: AsRef<[T]>RandomAccess<T>を実装することです。このように、それはあなたがそうあなたにもちょうど変更される場合がありますことを行う場合には、他のRandomAccess implsを追加することはできません、[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) 
} 

で動作しますfindAsRef<[T]>を満たすいくつかのコレクションを取るために:

fn find<T: Copy, C: AsRef<[T]>> (src: C, index: usize) -> T { 
    src.get_at(index) 
} 

を別の方法として、あなたは[T]として借りられないできるというコレクションをサポートできるようにする必要がある場合、あなたはを実装することができますマクロを使用して、いくつかの範囲内のすべてのnため[T; 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) 
} 

、あなただけのすべての[T; n]ためRandomAccess<T>を実装することができるはずです。しかし今のところ、マクロを使う必要があります。

+0

'AsRef'には、' [T; 32]。 – delnan

+1

より単純なバージョン( 'fn find (src:&[T])')の仕組みを説明できますか? '&[T; n]'を '&[T]'に強制するコンパイラの特別なケースですか? –

+1

これはバグです:https://github.com/rust-lang/rust/issues/29504。私は答えを更新しました。 – Steven

関連する問題