如何复制/克隆既不派生的结构?

时间:2017-02-21 15:01:06

标签: rust

我正在尝试使用Piston进行一些游戏编程,但我正在努力使用Copy,因为它没有派生Cloneextern crate piston_window; extern crate piston; extern crate graphics; extern crate opengl_graphics; use opengl_graphics::Texture as Tex; use piston_window::*; use std::path::Path; use opengl_graphics::GlGraphics; #[derive(PartialEq)] enum ObjectType { Blocking, Passing, } struct Object { sprite: Tex, obj_type: ObjectType, position: Position, } struct Game { gl: GlGraphics, images: Vec<Object>, player: Player, } struct Player { sprite: Tex, position: Position, } struct Position { x: i32, y: i32, } impl Game { fn render(&mut self, args: &RenderArgs) { let iter = self.images.iter(); let player = &self.player; self.gl.draw(args.viewport(), |c, g| { clear([1.0, 1.0, 1.0, 1.0], g); for img in iter { let pos = img.get_position(); let transform = c.transform.trans(((pos.x * 64)) as f64, ((pos.y * 64)) as f64); image(img.get_sprite(), transform, g); } image(player.get_sprite(), c.transform.trans((player.get_position().x * 64) as f64, (player.get_position().y * 64) as f64), g); }); } fn update(&mut self, args: &UpdateArgs) {} }

fn main() {
    let (width, height) = (64*10, 64*10);
    let opengl = OpenGL::V3_2;
    let mut window: PistonWindow =
        WindowSettings::new("piston", (width, height))
        .exit_on_esc(true)
        .opengl(opengl)
        .build()
        .unwrap();
    window.hide();
    println!("Loading...");
    let mut player = Player { sprite: Tex::from_path(&Path::new(
                            "./assets/player_n.png")).unwrap(),
                            position: Position { x: 3, y: 3 },
    };

    let mut game = Game {
        gl: GlGraphics::new(opengl),
        images: Vec::new(),
        player: player,
    };

    for i in 0..10 {
        for j in 0..10 {
            if i == 0 || i == 9 || j == 0 || j == 9 {
                let obj = Object { sprite: Tex::from_path(&Path::new(
                        "./assets/wall.png")).unwrap(),                                                 
                    obj_type: ObjectType::Blocking,
                        position: Position { x: i, y: j },
                };
                game.images.push(obj);

            } else {
                let obj = Object { sprite: Tex::from_path(&Path::new(
                        "./assets/floor.png")).unwrap(),                                                
                    obj_type: ObjectType::Passing,
                        position: Position { x: i, y: j },
                };
                game.images.push(obj);
            }
        }
    }
    window.show();
    while let Some(e) = window.next() {

        if let Some(Button::Keyboard(key)) = e.press_args() {
            let mut pos = game.player.position.clone();
            let mut spr: Option<Tex> = None;          
            match key {
                Key::Up => { pos.y -= 1; spr = Some(Tex::from_path(&Path::new(
                        "./assets/player_n.png")).unwrap()); },
                Key::Down => { pos.y += 1; spr = Some(Tex::from_path(&Path::new(
                        "./assets/player_s.png")).unwrap()); },
                Key::Left => { pos.x -= 1; spr = Some(Tex::from_path(&Path::new(
                        "./assets/player_w.png")).unwrap()); },              
                Key::Right => { pos.x += 1; spr = Some(Tex::from_path(&Path::new(
                        "./assets/player_e.png")).unwrap()); },
                _ => (),
            }
            for elem in game.images.iter() {
                if pos.x == elem.position.x && pos.y == elem.position.y && elem.obj_type == ObjectType::Passing {
                    game.player.position = pos;

                    game.player.sprite = spr.clone().unwrap();

                }
            }
        }        
        if let Some(r) = e.render_args() {
            game.render(&r);       
        }
        if let Some(u) = e.update_args() {
            game.update(&u); 
        }
    }
}

主要游戏循环:

error: no method named `clone` found for type `std::option::Option<opengl_graphics::Texture>` in the current scope
   --> src/main.rs:159:46
159 |                     game.player.sprite = spr.clone().unwrap();
    |                                              ^^^^^
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied: `opengl_graphics::Texture : std::clone::Clone`

产生错误:

opengl_graphics::Texture

我理解为什么会收到此错误,因为Copy未导出Option<opengl_texture>我无法克隆trait SyncCmsProxyService { def head(path: String): String def teaser(path: String): String } @Singleton class DefaultSyncCmsProxyService @Inject()(implicit cache: CacheApi, wsClient: WSClient) extends SyncCmsProxyService with UrlBuilder with CacheAccessor{ private val log = Logger("application") override def head(path: String) = { log.debug("looking for head ...") query(url(path), "$.payload[0].title") } override def teaser(path: String) = { log.debug("looking for teaser ...") query(url(path), "$.payload[0].content.teaserText") } private def query(url: String, jsonPath: String) = { val key = s"${url}?${jsonPath}" val payload = findInCache(key) if (payload.isDefined) { payload.get }else{ val json = Json.parse(body(url)) val queried = JSONPath.query(jsonPath, json).as[String] saveInCache(key, queried) } } private def body(url: String) = { cache.synchronized { val body = findInCache(url) if (body.isDefined) { log.debug("found body in cache") body.get } else { saveInCache(url, doCall(url)) } } } private def doCall(url : String): String = { import scala.concurrent.ExecutionContext.Implicits.global log.debug("calling...") val req = wsClient.url(url).get() val f = req map { res => val status = res.status log.debug(s"endpoint called! response status: ${status}") if (status == 200) { res.body } else { "" } } Await.result(f, 15.seconds) } } 。有什么办法解决这个问题?

我尝试弄乱引用,但这不起作用。

1 个答案:

答案 0 :(得分:4)

  

如何复制/克隆既不派生的结构?

你不是。你唯一能做的就是对它进行一些参考。

在这种情况下,图书馆选择不实施CloneCopy是一件非常好的事情。如果您能够克隆结构,那么您将经常和不必要地分配大量内存。相反,库已迫使您考虑何时分配该内存。其中一个解决方案是在应用程序启动时加载所有纹理并引用它们:

更改您的结构以保留参考:

#[derive(PartialEq)]
enum ObjectType {
    Blocking,
    Passing,
}

struct Object<'a> {
    sprite: &'a Tex,
    obj_type: ObjectType,
    position: Position,
}

struct Game<'a> {
    gl: GlGraphics,
    images: Vec<Object<'a>>,
    player: Player<'a>,
}

struct Player<'a> {
    sprite: &'a Tex,
    position: Position,
}

#[derive(Copy, Clone, PartialEq)]
struct Position {
    x: i32,
    y: i32,
}

struct Textures {
    player_n: Tex,
    player_s: Tex,
    player_e: Tex,
    player_w: Tex,
    wall: Tex,
    floor: Tex,
}

main中尽早加载纹理。请注意,Path需要明确使用AsRef<Path>

let textures = Textures {
    player_n: Tex::from_path("./assets/player_n.png").unwrap(),
    player_s: Tex::from_path("./assets/player_s.png").unwrap(),
    player_e: Tex::from_path("./assets/player_e.png").unwrap(),
    player_w: Tex::from_path("./assets/player_w.png").unwrap(),
    wall: Tex::from_path("./assets/wall.png").unwrap(),
    floor: Tex::from_path("./assets/floor.png").unwrap()
};

然后传递对这些纹理的引用:

match key {
    Key::Up => {
        pos.y -= 1;
        spr = Some(&textures.player_n)
    }
    Key::Down => {
        pos.y += 1;
        spr = Some(&textures.player_s)
    }
    Key::Left => {
        pos.x -= 1;
        spr = Some(&textures.player_w)
    }
    Key::Right => {
        pos.x += 1;
        spr = Some(&textures.player_e)
    }
    _ => (),
}
for elem in game.images.iter() {
    if pos == elem.position && elem.obj_type == ObjectType::Passing {
        game.player.position = pos;

        if let Some(spr) = spr {
            game.player.sprite = spr;
        }
    }
}

请注意,这也会合并可能发生错误的位置。在循环的内部不再有unwrap

由于代码不完整,我无法让您的代码完成编译,但这应该有助于开始:

error: no method named `render` found for type `Game<'_>` in the current scope
   --> src/main.rs:122:18
    |
122 |             game.render(&r);
    |                  ^^^^^^
    |
    = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `render`, perhaps you need to implement it:
    = help: candidate #1: `piston_window::RenderEvent`

error: no method named `update` found for type `Game<'_>` in the current scope
   --> src/main.rs:125:18
    |
125 |             game.update(&u);
    |                  ^^^^^^
    |
    = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `update`, perhaps you need to implement one of them:
    = help: candidate #1: `piston_window::UpdateEvent`
    = help: candidate #2: `piston_window::<unnamed>::UpdateTexture`
    = help: candidate #3: `deflate::checksum::RollingChecksum`
    = help: candidate #4: `cocoa::appkit::NSOpenGLContext`
    = help: candidate #5: `cocoa::appkit::NSOpenGLContext`