首页 文章

无法摆脱借来的内容和Builder模式

提问于
浏览
5

我只是在学习Rust . 我正在尝试为我的Game结构创建一个构建器结构 . 这是代码:

struct Input {
    keys_pressed: HashMap<VirtualKeyCode, bool>,
}

pub struct GameBuilder {
    settings: GameSettings,
    input: Input,
}

impl GameBuilder {
    pub fn new() -> GameBuilder {
        GameBuilder {
            settings: GameSettings {
                window_dimensions: (800, 600),
                title: "".to_string(),
            },
            input: Input {
                keys_pressed: HashMap::new(),
            }
        }
    }

    pub fn with_dimensions(&mut self, width: u32, height: u32) -> &mut GameBuilder {
        self.settings.window_dimensions = (width, height);
        self
    }

    pub fn with_title(&mut self, title: &str) -> &mut GameBuilder {
        self.settings.title = title.to_string();
        self
    }

    pub fn game_keys(&mut self, keys: Vec<VirtualKeyCode>) -> &mut GameBuilder {
        for key in keys {
            self.input.keys_pressed.insert(key, false);
        }
        self
    }

    pub fn build(&self) -> Game {
        let (width, height) = self.settings.window_dimensions;
        Game {
            display: glutin::WindowBuilder::new()
                        .with_dimensions(width, height)
                        .with_title(self.settings.title.to_string())
                        .build_glium()
                        .ok()
                        .expect("Error in WindowBuilder"),
            state: GameState::Running,
            input: self.input,
        }
    }
}

但是这段代码在最后一行 input: self.input 抱怨:

error: cannot move out of borrowed content

我想我理解为什么 . 由于在函数中传递的参数是 &self ,我不能取得它的所有权,以及最后一行正在做什么 .

我认为也许改变 &selfself 会起作用,但编译认为我不能改变 self .

还有我所知道的复制特征,也许应该可以解决问题 . 但是Input基本上是一个HashMap,这意味着如果散列本身太大,副本可能会很昂贵 .

如何解决这个问题的好方法?

编辑:

我试过这样做:

#[derive(Debug, Copy, Clone)]
struct Input {
    keys_pressed: HashMap<VirtualKeyCode, bool>,
}

但编译器抱怨:

error: the trait `Copy` may not be implemented for this type; field `keys_pressed` does not implement `Copy`

1 回答

  • 7

    鉴于您的方法签名是如何制定的,您似乎的目标是链接:

    let game = GameBuilder::new().with_dimensions(...)
                                 .with_title(...)
                                 .build();
    

    在Rust中,这要求 GameBuilder 按值传递:

    pub fn with_dimensions(self, ...) -> GameBuilder {
        // ...
    }
    

    并且为了能够在方法中变异 self ,您需要将其设为 mut

    pub fn with_dimensions(mut self, ...) -> GameBuilder {
    }
    

    如果您更改 with_dimensionswith_titlegame_keysbuild 的签名以取值 self (如果打算是 mut self ),则链接应该有效 .

相关问题