Изучая итераторы в Rust, я создал следующую структуру, чтобы скрыть реализацию двумерной коллекции:
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));
}
}
}
Есть ли соглашение или передовая практика для изменения внутренних членов структуры, при этом разрешая доступ к неизменяемым членам и методам? Или это полностью нарушает гарантии безопасности?
width
иheight
общедоступными? Кто угодно мог изменить свою ценность, и все сломалось! Вместо этого они должны быть представлены с помощью методов получения. - person Francis Gagné   schedule 29.10.2014