1

Rust のイテレータについて学習しているときに、次の構造体を作成して、2 次元コレクションの実装を非表示にしました。

use std::slice::{Items, MutItems};
use std::vec::{Vec};

pub struct Table<T> {
    pub width: uint,
    pub height: uint,
    data: Vec<T>
}

impl<T: Clone> Table<T> {
    pub fn from_elem(width: uint, height: uint, value: T) -> Table<T> {
        Table {
            width: width,
            height: height,
            data: Vec::from_elem(width * height, value)
        }
    }
}

impl<T> Table<T> {
    pub fn get_row_column(&self, index: uint) -> (uint, uint) {
        (index / self.width, index % self.width)
    }

    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        self.data.iter()
    }

    pub fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> {
        self.data.iter_mut()
    }
}

iterメソッドとメソッドの目的は、iter_mutこの構造体のユーザーが、データが行優先形式または列優先形式のどちらで格納されているかを気にする必要がないようにすることでした。イテレータは、最も効率的な順序で要素を提供するだけです。

ただし、このデータ構造を使用する場合、外部データを取得するために特定の行と列を知る必要があることがよくありました。

fn get_input(row: uint, column: uint) -> uint {
    row * 10 + column / 2
}

fn main() {
    let mut table = Table::from_elem(640, 480, 0u);

    for (index, value) in table.iter_mut().enumerate() {
        let (row, column) = table.get_row_column(index);
        *value = get_input(row, column);
    }
}

しかし、メソッドを呼び出そうとするとすぐにget_row_column、次のコンパイラ エラーが発生します。

main.rs:56:33: 56:38 error: cannot borrow `table` as immutable because it is also borrowed as mutable
main.rs:56             let (row, column) = table.get_row_column(index);
                                           ^~~~~
main.rs:55:31: 55:36 note: previous borrow of `table` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `table` until the borrow ends
main.rs:55         for (index, value) in table.iter_mut().enumerate() {
                                         ^~~~~
main.rs:59:6: 59:6 note: previous borrow ends here
main.rs:55         for (index, value) in table.iter_mut().enumerate() {
main.rs:56             let (row, column) = table.get_row_column(index);
main.rs:57             *value = get_input(row, column);
main.rs:58         }
main.rs:59     }
               ^

ここでやろうとしていることを達成する正しい方法は何ですか? 行番号と列番号を取得し、行インデックスと列インデックスを明示的にループするメソッドを追加できsetますが、ユーザーは行優先と列優先の順序について心配する必要があります。

impl<T> Table<T> {        
    fn get_index(&self, row: uint, column: uint) -> uint {
        row * self.width + column
    }

    pub fn set(&mut self, row: uint, column: uint, value: T) {
        let index = self.get_index(row, column);
        self.data[index] = value;
    }
}

fn main() {
    let mut table = Table::from_elem(640, 480, 0u);

    for row in range(0, table.height) {
        for column in range(0, table.width) {
            table.set(row, column, get_input(row, column));
        }
    }
}

不変のメンバーとメソッドへのアクセスを許可しながら、構造体の内部メンバーを変更するための規則またはベストプラクティスはありますか? それとも、安全保証に完全に違反していますか?

4

3 に答える 3