Альтернатива передаче вектора в функцию? - PullRequest
0 голосов
/ 26 января 2019

В настоящее время я изучаю ржавчину, написав проект, который является клоном настольной игры "Пуэрто-Рико".

структура Game: я выбрал элемент players в качестве среза массивапотому что он может содержать только 3, 4 или 5 игроков (на мой взгляд, это идеальный вариант использования среза массива внутри структуры вместо Vec)

функция Game::new: возвращаетновый Game экземпляр.Он берет список имен игроков и пустой Vec и заполняет его соответствующими Player экземплярами, а затем сохраняет его в Game как фрагмент массива.

Проблема в том, что этометод создания структуры Game кажется довольно громоздким, и я чувствую, что есть способ обойти его (например, передать только параметр names и как-то создать срез массива внутри функции new).

Итак, есть ли способ сделать это?Должен ли я просто изменить players член на Vec?

Я попытался переместить объявление vec!() в функцию new, но, конечно, он не работает, потому что его отбрасываютв конце блока.

use super::board::Board;
use super::player::Player;
use super::planatation::ResourceType;

#[derive(Debug)]
pub struct Game<'a> {

    board: Board,
    players: &'a [Player],
    governor: &'a Player
}

impl<'a> Game<'a> {

    pub fn new(names: &[String], players: &'a mut Vec<Player>) -> Self {
        let num_of_players = names.len() as i32;
        let board = Board::new(num_of_players);

        if num_of_players < 3 || num_of_players > 5 {
            panic!("Only 3, 4 or 5 players may play");
        }

        if num_of_players < 5 {
            for (i, name) in names.iter().enumerate() {
                if i < 2 {
                    players.push(Player::new(name.to_string(), ResourceType::Indigo));
                } else {
                    players.push(Player::new(name.to_string(), ResourceType::Corn));
                }
            }
        } else { // num_of_player == 5
            for (i, name) in names.iter().enumerate() {
                if i < 3 {
                    players.push(Player::new(name.to_string(), ResourceType::Indigo));
                } else {
                    players.push(Player::new(name.to_string(), ResourceType::Corn));
                }
            }
        }

        Game {
            board: board,
            players: players,
            governor: &players[0]
        }
    }
}

1 Ответ

0 голосов
/ 26 января 2019

Как вы уже заметили, срез не владеет своими данными, он только ссылается на них. Вот почему вы должны создавать игроков вне структуры и передавать их в структуру игры. Если вы хотите, чтобы ваша структура содержала игроков, они должны быть Vec вместо среза.

Если бы governor не был членом структуры, я бы предложил просто использовать Vec (или ArrayVec) и покончить с этим. Это, однако, означало бы, что governor не может (как правило) быть ссылкой на этот самый вектор (см. Почему я не могу сохранить значение и ссылку на это значение в одной и той же структуре? ).

В зависимости от точной семантики и вариантов использования governor и других «обычных» игроков, я бы сделал одно из следующих действий:

  • Наличие Vec (или ArrayVec) для «обычных» игроков и дополнительное поле для губернатора. Это может быть громоздким, если вам часто приходится делать то же самое как для «обычных» игроков, так и для губернатора, но вы можете ввести метод, который возвращает итератор для всех игроков и управляющего.
  • Наличие Vec (или ArrayVec) для всех игроков, и просто сохраните индекс в векторе для губернатора. Как вариант, вы можете установить, что губернатор всегда является элементом first в Vec, в котором содержатся все игроки.
  • Делай, как ты уже сделал. (Это, однако, может означать, что вы не можете легко изменить их (потому что вы можете иметь только одну изменяемую ссылку за раз). Вы можете обойти это посредством внутренней изменчивости, но я не уверен, стоит ли это того)
  • Храните только Vec<String> с именами игроков. Исходя из этого, вы можете получить количество игроков. Если тип игрока достаточно прост, вам может не хватить даже явного хранения игроков, но вывести тип игрока по его индексу (что, я полагаю, возможно из-за того, как вы определяете Indigo или Corn ). Недостатком является то, что у вас нет игрока вокруг, но, возможно, вы можете смоделировать всю игру без них.
...