复制/移动未实现复制的字段

费里斯船长有一张地图 ( seven_seas.png),显示他隐藏了多个宝藏(在坐标 (5,7) 和 (7,9) 处)。他想为每个宝藏创建一个单独的藏宝图。不应更改原始地图。

为此,他决定使用 Rust 和图像箱。

extern crate image;
use crate::image::GenericImage;


struct Desk {
    map_of_seven_seas: image::DynamicImage,
    colored_ink: image::Rgba<u8>,
}

impl Desk {
    fn create_treasure_map(mut self, x: u32, y:u32) -> image::DynamicImage {
        self.map_of_seven_seas.put_pixel(x, y, self.colored_ink);
        self.map_of_seven_seas
    }

}

fn main() {
    let desk = Desk {
        map_of_seven_seas: image::open("seven_seas.png").unwrap(),
        colored_ink: image::Rgba([255, 0, 0, 255]), // red             
    };

    println!("Marking my treasures!");
    // works fine
    let treasure_map_0 = desk.create_treasure_map(5, 7);
    treasure_map_0.save("treasure_map_0.png").unwrap();

    // breaks
    let treasure_map_1 = desk.create_treasure_map(7, 9);
    treasure_map_1.save("treasure_map_1.png").unwrap();
}

乌云遮蔽了天空,费里斯船长意识到他的计划存在缺陷:

error[E0382]: use of moved value: `desk`
  --> src/main.rs:30:26
   |
19 |     let desk = Desk {
   |         ---- move occurs because `desk` has type `Desk`, which does not implement the `Copy` trait
...
26 |     let treasure_map_0 = desk.create_treasure_map(5, 7);
   |                          ---- value moved here
...
30 |     let treasure_map_1 = desk.create_treasure_map(7, 9);
   |                          ^^^^ value used here after move

error: aborting due to previous error

费里斯船长现在有麻烦了。好像他的办公桌只能用一次。他评估了 Mate Cargo 暗示的内容,并尝试为 Desk 推导出 Copy trait(添加#[derive(Clone, Copy)]到结构中)。但他又一次失败了:

error[E0204]: the trait `Copy` may not be implemented for this type
 --> src/main.rs:4:17
  |
4 | #[derive(Clone, Copy)]
  |                 ^^^^
5 | struct Desk {
6 |     map_of_seven_seas: image::DynamicImage,
  |     -------------------------------------- this field does not implement `Copy`
  |
  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

image::DynamicImage无法复制,他也无法推导Copy出来,因为它是板条箱的一部分。

费里斯船长每次要创建藏宝图(包括从文件系统加载map_of_the_seven_seas)是否都要创建一个新的Desk?或者有更好的方法来重用办公桌吗?

这对我来说是一个学习练习,所以一个很好的解释解决方案比一个聪明的黑客更好。

回答

费里斯船长每次要创建藏宝图(包括从文件系统加载map_of_the_seven_seas)是否都要创建一个新的Desk?或者有更好的方法来重用办公桌吗?

确实有更好的方法。这里的问题是

fn create_treasure_map(mut self, x: u32, y:u32) -> image::DynamicImage

self参数(是否mut与否)指在调用此方法消耗的办公桌。虽然推导Clone是可能的(Copy绝对不是),但它确实每次都会复制整个桌子,这似乎是不必要的。

但是,这是可以避免的,通过使用方法借用self 代替:

fn create_treasure_map(&mut self, x: u32, y:u32) -> &image::DynamicImage {
    self.map_of_seven_seas.put_pixel(x, y, self.colored_ink);
    &self.map_of_seven_seas
}

但是请注意,此更新map_of_seven_seas原地的,意义treasure_map_1包含指出宝藏treasure_map_0

我认为这是不可取的,因为这对于第二张地图的持有者来说太容易了,而宁愿击败通常的藏宝图点。

解决办法是不更新桌子:只借用它不变(我们不需要更新它或它的七海“参考”地图)并在添加取景位置之前只复制地图:

fn create_treasure_map(&self, x: u32, y:u32) -> image::DynamicImage {
    let mut treasure_map = self.map_of_seven_seas.clone();
    treasure_map.put_pixel(x, y, self.colored_ink);
    treasure_map
}


以上是复制/移动未实现复制的字段的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>