Rust нужна помощь в рефакторинге лишних функций - PullRequest
0 голосов
/ 28 мая 2020

(я должен упомянуть, что я новичок в ржавчине)

привет! Я создаю двумерную симуляционную игру с использованием Ve c для хранения структур с информацией о каждой частице. прямо сейчас мне нужно писать отдельную функцию каждый раз, когда я хочу проверить, касается ли элемент чего-то с определенным свойством. в основном он ищет вокруг частицы по кругу, вычисляя индекс этой позиции, а затем сравнивает это свойство структуры с целевым свойством следующим образом: всевозможные свойства и взаимодействия. Мне действительно интересно, есть ли способ уменьшить это до одной функции. Я уже некоторое время возился с этим самостоятельно и не смог добиться какого-либо прогресса. Проблема, с которой я сталкиваюсь, заключается в том, что сравнение должно быть вычислено в функции и не может быть передано, насколько я могу судить. есть ли способ исправить это? например, сделать так, чтобы я передал что-то, что говорит, какое поле структуры я хочу сравнить после того, как он вычислит индекс структуры?

Ответы [ 3 ]

1 голос
/ 29 мая 2020

Мне удалось найти решение!

pub fn check_touch(screen: &mut Vec<Particle>, x_pos: usize, criteria: impl Fn(Particle) -> bool,) -> usize {
    if criteria(screen[calc::ul(x_pos)]) {return calc::ul(x_pos)}
    //do this for every direction
}

затем назовите его как

check_touch(screen, x_pos, |p| p.corrode)

кредит r / Erelde на Reddit за то, что он дал мне совет

1 голос
/ 28 мая 2020

Думаю, вам нужно что-то вроде этого:

// The function returns a tuple of indices, instead of having two functions that return one index each
pub fn check_touch_corrode_flammable(screen: &mut Vec<Particle>, x_pos: usize) -> (usize, usize) {

  let mut results : (usize, usize) = (x_pos, x_pos);

  // We keep track so that we can skip checking cells  
  let mut found_corr = false;
  let mut found_flam = false;

  let ul = screen[calc::ul(x_pos)];

  if ul.corrode {
    results.0 = ul;
    found_corr = true;
  }

  if ul.flammable {
    results.1 = ul;
    found_flam = true;
  }

  let u = screen[calc::u(x_pos)];

  if !found_corr && u.corrode {
    results.0 = u;
    found_corr = true;
  }

  if !found_flam && u.flammable) {
    results.1 = u;
    found_flam = true;
  }

  let ur = screen[calc::ur(x_pos)];

  if !found_corr && ur.corrode {
    results.0 = ur;
    found_corr = true;
  }

  if !found_flam && ur.flammable) {
    results.1 = ur;
    found_flam = true;
  }

  // Continuing like this...

  // ...

  // And then at the end:

  let dr = screen[calc::dr(x_pos)];

  if !found_corr && dr.corrode {
    results.0 = dr;
    found_corr = true;
  }

  if !found_flam && dr.flammable) {
    results.1 = dr;
    found_flam = true;
  }

  results
}

Главное преимущество этого решения в том, что оно вычисляет индексы для проверяемых нами ячеек в каждом направлении только один раз. Это более или менее то, что вам нужно? Дай мне знать, нужна ли тебе дополнительная помощь :)

0 голосов
/ 29 мая 2020

Я бы go в этом направлении, с итераторами, фильтрами и предикатами:

fn neighbors(x_pos: usize) -> impl 'static + Iterator<Item=usize> {
    (0..8).map(move |n| match n {
        0 => calc_ul(x_pos),
        1 => calc_u(x_pos),
        // and so on for 2-7

        _ => panic!("shouldn't get hereA"),
    })
}

fn first_corrosive_neighbor(screen: &Vec<Particle>, x_pos: usize) -> Option<usize> {
    neighbors(x_pos).filter(|p| screen[*p].corrode).next()
}

fn first_flammable_neighbor(screen: &Vec<Particle>, x_pos: usize) -> Option<usize> {
    neighbors(x_pos).filter(|p| screen[*p].flammable).next()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...