Привет.
Делаю бота условно назовём его Bot1
, он хранит некоторый путь path
, просто вектор точек, и также текущий участок пути, который логично (наверное) представить как слайс.
struct Bot1<'a> {
random: RefCell<IsaacRng>,
path: Vec<Point>,
cur_view: &'a[Point]
}
Понятно, что я тут же получил кучу ошибок от BC. Очевидный выход использовать индекс начала и конца, но он мне не нравится - придётся вручную отслеживать выходы за пределы path
, считать попадание в участок пути и вообще неудобно.
Какие альтернативы ещё есть?
Моя наивная попытка здесь
2 лайка
Мне кажется что втупую через индексы - самый практичный путь, по крайней мере с точки зрения сложности кода.
UPD: Потому что самоссылающиеся структуры в расте это боль, по крайней мере пока https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md не приняли. Есть всякие костыльные штуки вроде https://crates.io/crates/rental + можно заморочиться с Rc.
По мне так сильно проще замутить небольшую абстракцию с индексами 
1 лайк
А, раньше казалось что Pin-ы это что-то слишком абстрактное и мне точно не понадобится, ан нет…
На ум приходит что-то вроде структуры данных “вектор с окном”, чтобы можно было менять вектор, и окно соответственно тоже бы менялось.
Попробую такую абстракцию реализовать.
Спасибо.
Ну как, получилось что-то с реализацией этой штуки?
Сделал просто индексом:
#[derive(Clone, Debug)]
pub struct Bot2 {
...
path: Vec<P>,
path_idx: usize,
...
}
Недостаток в том, что теперь в месте использования приходится всегда проверять выход индекса за пределы массива:
let the_move = if !self.path.is_empty() && self.path_idx < self.path.len() {
let new_head = self.path[self.path_idx];
...
}
И когда self.path
меняется, нужно не забыть пододвинуть self.path_idx
нужным образом. И, наконец, если вышли за пределы, то … непонятно что делать. Панику кидать не хочется, как-то надо сигнализировать о нарушении инварианта и восстановить инвариант.
Что-то хочется, чтобы индекс имел тип “индекс в векторе path” и больше гарантий от компилятора.
Т.е. ты не стал путь и индексвы в одну структуру с удобными методами упаковывать? А то можно было бы Result возвращать какой-нибудь и просто ?
ом пробрасывать его наверх, если что не так. Или проверять где надо.
Уже сделано в крейте rental, но, судя по количеству загрузок, решение не очень популярное.
Я было начал, но потом меня испугало то, что нужно повторять часть апи для вектора для этой структуры тоже, итераторы всякие и так далее. Как-нибудь потом 
1 лайк
Я совсем недавно в rust, поэтому могу многое не знать, но скажите почему такое решение хуже, чем с отдельными индексами ? Если вы такое рассматривали конечно.
Из того что сразу в голову приходит (может еще что есть), такую структуру нельзя будет нормально переместить или передать по &mut
ссылке:
fn f1(_b: &mut Bot1) {}
fn f2(_b: Bot1) {}
...
f1(&mut b1);
f2(b1);
error[E0502]: cannot borrow `b1` as mutable because `b1.path` is also borrowed as immutable
--> src/main.rs:40:13
|
36 | b1.cur_view = &b1.path[2..];
| ------- immutable borrow occurs here
...
40 | f1(&mut b1);
| ^^ mutable borrow occurs here
...
44 | }
| - immutable borrow ends here
error[E0505]: cannot move out of `b1` because it is borrowed
--> src/main.rs:41:8
|
36 | b1.cur_view = &b1.path[2..];
| ------- borrow of `b1.path` occurs here
...
41 | f2(b1);
| ^^ move out of `b1` occurs here
Playground
Хммм точно, сразу как то в голову не пришло )) Спасибо. Как то еще не смог полностью поменять мышление, не улавливаю такие моменты сразу.
я бы делал структуру, с вектором и с индексами текущего начала и конца (Range например).
и эти индексы делал бы приватными.
А публично выставил бы только метод (функцию), вызов которого возвращал бы слайсы с параметрами согласно инфы содержащейся в индесах,.