Generics Rust需要帮助重构过多的函数

Generics Rust需要帮助重构过多的函数,generics,struct,rust,refactoring,Generics,Struct,Rust,Refactoring,(我应该提一下,我是个新手) 嗨!我正在构建一个2d粒子模拟游戏,使用Vec来保存包含每个粒子信息的结构。现在,每当我想检查元素是否接触到具有特定属性的对象时,我都需要编写一个单独的函数。基本上,它通过计算该位置的索引来搜索圆中的粒子,然后将该结构属性与目标属性进行比较,如下所示: //check around particle for corrodable particles pub fn check_touch_corrode(screen: &mut Vec<Particle

(我应该提一下,我是个新手)

嗨!我正在构建一个2d粒子模拟游戏,使用Vec来保存包含每个粒子信息的结构。现在,每当我想检查元素是否接触到具有特定属性的对象时,我都需要编写一个单独的函数。基本上,它通过计算该位置的索引来搜索圆中的粒子,然后将该结构属性与目标属性进行比较,如下所示:

//check around particle for corrodable particles
pub fn check_touch_corrode(screen: &mut Vec<Particle>, x_pos: usize) -> usize {
    if screen[calc::ul(x_pos)].corrode {return calc::ul(x_pos)}     //if particle can corrode return particle
    if screen[calc::u(x_pos)].corrode {return calc::u(x_pos)}
    if screen[calc::ur(x_pos)].corrode {return calc::ur(x_pos)}
    if screen[calc::l(x_pos)].corrode {return calc::l(x_pos)}
    if screen[calc::r(x_pos)].corrode {return calc::r(x_pos)}
    if screen[calc::dl(x_pos)].corrode {return calc::dl(x_pos)}
    if screen[calc::d(x_pos)].corrode {return calc::d(x_pos)}
    if screen[calc::dr(x_pos)].corrode {return calc::dr(x_pos)}
    x_pos                                                           //else return own position
}

//check around particle for flammable particle
pub fn check_touch_flammable(screen: &mut Vec<Particle>, x_pos: usize) -> usize {
    if screen[calc::ul(x_pos)].flammable {return calc::ul(x_pos)}   //if particle flammable return particle
    if screen[calc::u(x_pos)].flammable {return calc::u(x_pos)}
    if screen[calc::ur(x_pos)].flammable {return calc::ur(x_pos)}
    if screen[calc::l(x_pos)].flammable {return calc::l(x_pos)}
    if screen[calc::r(x_pos)].flammable {return calc::r(x_pos)}
    if screen[calc::dl(x_pos)].flammable {return calc::dl(x_pos)}
    if screen[calc::d(x_pos)].flammable {return calc::d(x_pos)}
    if screen[calc::dr(x_pos)].flammable {return calc::dr(x_pos)}
    x_pos                                                           //else return own position
}
//检查颗粒周围是否有可腐蚀颗粒
发布fn检查触摸腐蚀(屏幕:&mut Vec,x位置:usize)->usize{
如果屏幕[calc::ul(x_pos)]。腐蚀{返回calc::ul(x_pos)}//如果粒子可以腐蚀返回粒子
如果屏幕[calc::u(x_位置)]。腐蚀{返回calc::u(x_位置)}
如果屏幕[calc::ur(x_pos)]。腐蚀{返回calc::ur(x_pos)}
如果屏幕[calc::l(x_pos)]。腐蚀{返回calc::l(x_pos)}
如果屏幕[calc::r(x_pos)]。腐蚀{返回calc::r(x_pos)}
如果屏幕[calc::dl(x_pos)]。腐蚀{返回calc::dl(x_pos)}
如果屏幕[calc::d(x_pos)]。腐蚀{返回calc::d(x_pos)}
如果屏幕[calc::dr(x_pos)]。腐蚀{返回calc::dr(x_pos)}
x_pos//否则返回自己的位置
}
//检查颗粒周围是否有易燃颗粒
pub fn check_touch_易燃(屏幕:&mut Vec,x位置:usize)->usize{
如果屏幕[calc::ul(x_位置)]。易燃{返回calc::ul(x_位置)}//如果粒子易燃返回粒子
如果屏幕[calc::u(x_位置)]。易燃{返回calc::u(x_位置)}
如果屏幕[calc::ur(x_位置)]。易燃{返回calc::ur(x_位置)}
如果屏幕[calc::l(x_位置)]。易燃{返回calc::l(x_位置)}
如果屏幕[calc::r(x_pos)]。易燃{返回calc::r(x_pos)}
如果屏幕[calc::dl(x_位置)]。易燃{返回calc::dl(x_位置)}
如果屏幕[calc::d(x_pos)]。易燃{返回calc::d(x_pos)}
如果屏幕[calc::dr(x_pos)]。易燃{返回calc::dr(x_pos)}
x_pos//否则返回自己的位置
}

考虑到im计划拥有数百个具有各种不同属性和交互的元素,这并不是真正可扩展的。我真的想知道是否有任何方法可以把它简化为一个函数。我一个人胡闹了一段时间,一直没能取得任何进展。我遇到的问题是,比较需要在函数中计算,并且据我所知,不能传入。有办法解决这个问题吗?比如说,在计算出结构索引后,我传递一个信息,告诉你我要比较结构的哪个字段?

我想你需要这样的信息:

//该函数返回一个索引元组,而不是两个函数各返回一个索引
酒吧fn检查触摸腐蚀易燃(屏幕:&mut Vec,x位置:usize)->(usize,usize){
让mut结果:(usize,usize)=(x_pos,x_pos);
//我们保持跟踪以便跳过检查单元格
让mut found_corr=false;
让mut find_flam=false;
设ul=screen[calc::ul(x_pos)];
如果ul腐蚀{
结果:0=ul;
found_corr=true;
}
如果ul是易燃的{
结果:1=ul;
found_flam=true;
}
设u=屏幕[计算::u(x_位置)];
如果!发现腐蚀(&u){
结果:0=u;
found_corr=true;
}
如果!发现(易燃和易燃){
结果:1=u;
found_flam=true;
}
设ur=屏幕[计算::ur(x_位置)];
如果!发现腐蚀{
结果:0=ur;
found_corr=true;
}
如果发现(易燃和不易燃){
结果:1=ur;
found_flam=true;
}
//继续这样下去。。。
// ...
//最后:
让dr=屏幕[计算::dr(x_位置)];
如果!发现腐蚀{
结果:0=dr;
found_corr=true;
}
如果!发现(易燃和不易燃){
结果:1=dr;
found_flam=true;
}
结果
}
此解决方案的主要优点是,它只计算我们在每个方向上检查的单元格的索引一次


这或多或少是你需要的吗?让我知道你是否需要更多帮助:)

我设法找到了解决办法

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
}

reddit上的r/Erelde给了我建议,这要归功于他

我会朝这个方向走,使用迭代器、过滤器和谓词:

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()
}
fn邻居(x_pos:usize)->impl'静态+迭代器{
(0..8).地图(移动| n |匹配n){
0=>calc_ul(x_位置),
1=>calc_(x_位置),
//以此类推,时间为2-7天
_=>恐慌!(“不应该到这里来”),
})
}
fn第一个\u邻居(屏幕:&Vec,x\u位置:usize)->选项{
邻居(x|u位置)。过滤器(| p |屏幕[*p]。腐蚀)。下一个()
}
fn第一个\u邻居(屏幕:&Vec,x\u位置:usize)->选项{
邻居(x|u位置)。过滤器(| p |屏幕[*p]。易燃)。下一个()
}

非常感谢您的回复!不幸的是,我不认为这将为我在这里试图做的工作。这不仅不能很好地扩展,而且我不想同时检查每一处房产。我的目标是有一个函数,我可以告诉你在周围的粒子中寻找一个特定的属性。现在我通过为每个属性编写一个单独的函数来实现这一点,但理想情况下,我只希望有一个函数,它接受一个包含我要搜索的属性的变量,然后扫描周围的粒子以查找该属性!好吧,我误解了。顺便说一句,很高兴你找到了解决方案,祝贺你!FWIW另一个可能的改进是迭代一部分属性(它们都应该是
fn(usize)->bool
),例如
对于dir in&[calc::ul,calc::u,calc::ur,…]{……
,尽管Optimizer可能对此不太满意。
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()
}