Как избежать дублирования при инициализации полей

Привет.

Беспокоит такое:

impl Bot2 {
    pub fn new(idx: u8) -> Self {
        Bot2 {
            idx: idx as usize,
            random: Rc::new(RefCell::new(IsaacRng::from_entropy())),
            m: 0,
            n: 0,
            cur_me: vec![],
            last_me: vec![],
            path: vec![],
            path_idx: 0,
            stay_count: 0,
            all: vec![],
            chasing: false,
        }
    }
}

impl Bot for Bot2 {
    fn reset(&mut self, gs: &GameState, idx: u8, seed: u64) {
        // must be like self.* = Bot2::new(idx).*;
        self.idx = idx as usize;
        self.random = Rc::new(RefCell::new(IsaacRng::new_from_u64(seed)));
        self.m = gs.field.m;
        self.n = gs.field.n;
        self.cur_me = vec![];
        self.last_me = vec![];
        self.path = vec![];
        self.path_idx = 0;
        self.stay_count = 0;
        self.all = vec![];
        self.chasing = false;
    }
...
}

В глаза бросается большой кусок повторяющегося кода. Нельзя ли сделать что-то вроде

  self = Bot2::new(idx); // oops, invalid Rust code
  self.random = Rc::new(RefCell::new(IsaacRng::new_from_u64(seed)));
  self.m = gs.field.m;
  self.n = gs.field.n;

или наоборот, fn new определить как-то? У меня уже был баг из-за того, что я забыл присвоить значение полю в fn reset и я хотел бы впредь избежать подобных ошибок.

Просто сделать *self = Bot2::new(idx) ? :slight_smile:

#[derive(Debug)]
struct Foo {
    a: i32
}

impl Foo {
    pub fn new(a: i32) -> Self {
        Self {
            a
        }
    }

    pub fn bar(&mut self) {
        *self = Self::new(10);
    }
}

fn main() {
    let mut foo = Foo::new(5);
    println!("{:?}", foo);
    foo.bar();
    println!("{:?}", foo);
}
3 симпатии

Ухты, оказывается так просто! :+1:
Да, отлично, всё работает.

А Default::default() не сойдет?

Можно, но не хотелось делать Option-ом idx, по той же причине, что значения любого id (user_id, product_id) не бывает по-умолчанию.
(Хотя, в данном случае это какой-нибудь -1 и тип не u, и тогда есть риск поиметь выход за пределы массива, Option надёжнее).

Не надо ничего кодировать специальными значениями, это антипаттерн наоборот. NonZero как раз для того и придумали, чтобы Option занимал столько же места. На уровне типов мы в безопасности, в рантайме все оптимизируется.