やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Rust自習(連結リスト8)

 std::ops::Indexトレイトのindexメソッドをオーバーライドした。

成果物

std::ops::Indexトレイトのindexメソッド

 list[index]みたいな表記で不変参照を得たい。そのためにはstd::ops::Indexトレイトのindexメソッドをオーバーライドすればいいと判明。

 トレイトは以下のように定義されている。

pub trait Index<Idx> where Idx: ?Sized {
    type Output: ?Sized;
    fn index(&'a self, index: Idx) -> &'a Self::Output;
}

オーバーライド

 これを任意の構造体に実装するときは以下のように書く。

struct MyStruct;
impl std::ops::Index<usize> for MyStruct {
    type Output = Option<i32>;
    fn index(&self, index: usize) -> &Self::Output { &None }
}
fn main() {
    let s = MyStruct{};
    println!("{:?}", s[0])
}
$ rustc main.rs
$ ./main
None

コード

 今回はジェネリック型を交えて書くので以下。

impl<T> std::ops::Index<usize> for LinkedList<T> {
    type Output = T;
    fn index(&self, index: usize) -> &Self::Output {
        fn get_ptr_from_idx<T>(ptr: &Option<Box<Node<T>>>, index: usize, count: usize) -> &Option<Box<Node<T>>> {
            if count < index {
                if ptr.is_some() { return get_ptr_from_idx(&ptr.as_ref().unwrap().next, index, count+1); }
                else { return ptr; }
            } else { return ptr; }
        }
        if let Some(ref _n) = get_ptr_from_idx(&self.head, index, 0) { return &(_n.item) }
        else { panic!("Out of index. index値が大きすぎます。index: {:?}", index); }
    }
}

テストコード

    #[test]
    #[should_panic(expected = "Out of index. index値が大きすぎます。index: 0")]
    fn LinkedList_index_out_of_index_0() {
        let mut list: LinkedList<i32> = LinkedList::new();
        list[0];
    }
    #[test]
    #[should_panic(expected = "Out of index. index値が大きすぎます。index: 1")]
    fn LinkedList_index_out_of_index_1() {
        let mut list: LinkedList<i32> = LinkedList::new();
        list.push(10);
        list[1];
    }
    #[test]
    fn LinkedList_index_1() {
        let mut list: LinkedList<i32> = LinkedList::new();
        list.push(10);
        assert_eq!(list[0], 10);
    }
    #[test]
    fn LinkedList_index_3() {
        let mut list: LinkedList<i32> = LinkedList::new();
        list.push(10);
        list.push(20);
        list.push(30);
        assert_eq!(list[0], 10);
        assert_eq!(list[1], 20);
        assert_eq!(list[2], 30);
    }

所感

 ついに[index]演算子のオーバーライドができた! この調子で代入できるIndexMutも実装しよう。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux

前回まで