将从结构借用的值传递回结构上的方法

问题描述 投票:0回答:1

我是 Rust 新手,尝试从 python 移植一些代码。我想询问一个特征的对象集合,对其进行一些过滤,然后将对象传递回该特征的方法,使其选择并返回其中一个对象。由于尝试多次借用,借用检查器给我一个错误;

cannot borrow *player as mutable when already borrowed as immutable

示例:

use std::borrow::Borrow;

trait Player {
    fn items(&self) -> Vec<&Item>;
    fn items_mut(&mut self) -> Vec<&mut Item>;
    fn should_choose_item<I: Borrow<Item>>(&self, possible_items: &Vec<I>) -> bool;
    fn choose_item<'a>(&'a self, _possible_items: Vec<&'a mut Item>) -> &'a mut Item;
}

#[derive(Debug)]
struct Item {
    can_choose: bool,
    level: u8,
}

fn method<'a, P: Player>(player: &'a mut P) -> &'a mut Item {
    let mut possible_items = player.items();
    possible_items.retain(|dwarf| dwarf.can_choose);

    if player.should_choose_item(&possible_items) {
        let mut possible_items = player.items_mut();
        possible_items.retain(|i| i.can_choose);
        return player.choose_item(possible_items);
    }
    let mut possible_items = player.items_mut();
    possible_items.retain(|i| i.can_choose);
    possible_items.pop().unwrap()
}

就像我提到的,我仍在学习 Rust,所以如果有更好的架构来做到这一点(从特征对象获取一些状态,以某种方式处理它,然后传回特征),我会有兴趣听听吧。

rust borrow-checker
1个回答
0
投票

不完全了解您在这里想要做什么,我做出了一些我认为您想要做什么以及在这种情况下我会做什么的决定,仅供您参考

trait IPlayer {
    fn items(&self) -> &Vec<Item>;
    fn items_mut(&mut self) -> &mut Vec<Item>;

    /* If you only use what inside the trait block you can have implementation of the function */
    fn get_level(&self) -> u8; // <-- here I added one more interface to get player's level

    fn should_choose(&self) -> bool {
        /*  this function will look through all item to see if there are item that are
            1 ) can_choose, and
            2 ) lower or equal to player's level
        */
        self
        .items()
        .iter()
        .fold(false, |acc, d| {
            (d.can_choose && d.level <= self.get_level()) || acc
        })
    }
    fn choose_item(&mut self) -> &mut Item {
        /*  this function will look through all item to pick the first item that
            1 ) can_choose, and
            2 ) lower or equal to player's level
            assuming such items exist therefore we unrwap the result

            *** notice this is not recommended, you should return a Option<>, but here I follow your code ***
        */
        let l = self.get_level();
        self.items_mut()
            .iter_mut()
            .filter(|d| d.can_choose && d.level <= l)
            .next()
            .unwrap()
    }
}

#[derive(Debug)]
struct Item {
    can_choose: bool,
    level: u8,
}

struct Dwarf {
    level: u8,
    player_items: Vec<Item>,
}
impl IPlayer for Dwarf {
    fn items(&self) -> &Vec<Item> { &self.player_items }
    fn items_mut(&mut self) -> &mut Vec<Item> { &mut self.player_items }
    fn get_level(&self) -> u8 {
        self.level
    }
}

fn main() {
    let mut dwarf = Dwarf {
        level: 1,
        player_items: vec![
            Item {
                can_choose: true,
                level: 1,
            },
            Item {
                can_choose: true,
                level: 2,
            },
            Item {
                can_choose: false,
                level: 1,
            },
            Item {
                can_choose: false,
                level: 2,
            },
        ],
    };

    println!("{:?}", dwarf.should_choose()); // "true"
    println!("{:?}", dwarf.choose_item());   // "Item { can_choose: true, level: 1 }"
}
© www.soinside.com 2019 - 2024. All rights reserved.