如何返回两个借用的RefCell的组合?

时间:2019-06-26 17:16:58

标签: rust iterator borrowing

我有一个结构,其中两个Vec包裹在RefCell中。我想在该结构上有一个方法,将两个向量结合起来并以新的RefCellRefMut的形式返回它们:

use std::cell::{RefCell, RefMut};

struct World {
    positions: RefCell<Vec<Option<Position>>>,
    velocities: RefCell<Vec<Option<Velocity>>>,
}

type Position = i32;
type Velocity = i32;

impl World {
    pub fn new() -> World {
        World {
            positions: RefCell::new(vec![Some(1), None, Some(2)]),
            velocities: RefCell::new(vec![None, None, Some(1)]),
        }
    }

    pub fn get_pos_vel(&self) -> RefMut<Vec<(Position, Velocity)>> {
        let mut poses = self.positions.borrow_mut();
        let mut vels = self.velocities.borrow_mut();

        poses
            .iter_mut()
            .zip(vels.iter_mut())
            .filter(|(e1, e2)| e1.is_some() && e2.is_some())
            .map(|(e1, e2)| (e1.unwrap(), e2.unwrap()))
            .for_each(|elem| println!("{:?}", elem));
    }
}

fn main() {
    let world = World::new();

    world.get_pos_vel();
}

如何将向量的压缩内容作为新的RefCell返回?有可能吗?

我知道有RefMut::map(),我试图嵌套两个对map的调用,但没有成功。

2 个答案:

答案 0 :(得分:1)

如果要返回新的Vec,则无需将其包装在RefMutRefCell中:

基于您的带有filtermap的代码

pub fn get_pos_vel(&self) -> Vec<(Position, Velocity)> {
    let mut poses = self.positions.borrow_mut();
    let mut vels = self.velocities.borrow_mut();

    poses.iter_mut()
        .zip(vels.iter_mut())
        .filter(|(e1, e2)| e1.is_some() && e2.is_some())
        .map(|(e1, e2)| (e1.unwrap(), e2.unwrap()))
        .collect()
}

替代filter_map

poses.iter_mut()
    .zip(vels.iter_mut())
    .filter_map(|pair| match pair {
        (Some(e1), Some(e2)) => Some((*e1, *e2)),
        _ => None,
    })
    .collect()

如果确实愿意,可以使用RefCell将其包装在RefCell::new中,但是我将由函数的用户将其包装在他们需要的任何地方。

答案 1 :(得分:1)

您希望能够修改位置和速度。如果必须将它们存储在两个单独的RefCell中,那么如何回避问题并使用回调进行修改呢?

use std::cell::RefCell;

struct World {
    positions: RefCell<Vec<Option<Position>>>,
    velocities: RefCell<Vec<Option<Velocity>>>,
}

type Position = i32;
type Velocity = i32;

impl World {
    pub fn new() -> World {
        World {
            positions: RefCell::new(vec![Some(1), None, Some(2)]),
            velocities: RefCell::new(vec![None, None, Some(1)]),
        }
    }

    pub fn modify_pos_vel<F: FnMut(&mut Position, &mut Velocity)>(&self, mut f: F) {
        let mut poses = self.positions.borrow_mut();
        let mut vels = self.velocities.borrow_mut();

        poses
            .iter_mut()
            .zip(vels.iter_mut())
            .filter_map(|pair| match pair {
                (Some(e1), Some(e2)) => Some((e1, e2)),
                _ => None,
            })
            .for_each(|pair| f(pair.0, pair.1))
    }
}

fn main() {
    let world = World::new();

    world.modify_pos_vel(|position, velocity| {
        // Some modification goes here, for example:
        *position += *velocity;
    });
}