rust 预期数组具有固定大小的x个元素,找到了一个具有y个元素的数组

nfzehxib  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(101)

我试图改变图标(我使用image crate加载)的应用程序的基础上的设备,应用程序正在编译。不幸的是,当尝试运行代码时:

let (icon_rgba, icon_width, icon_height) = {
        let icon = if cfg!(target_os = "macos") {
            include_bytes!("../assets/icon-macos.png")
        } else {
            include_bytes!("../assets/icon.png")
        };
        let image = image::load_from_memory(icon)
            .expect("Failed to open icon path")
            .into_rgba8();
        let (width, height) = image.dimensions();
        let rgba = image.into_raw();
        (rgba, width, height)
    };

我得到以下错误:

error[E0308]: `if` and `else` have incompatible types
 --> src/main.rs:6:13
  |
3 |           let icon = if cfg!(target_os = "macos") {
  |  ____________________-
4 | |             include_bytes!("../assets/icon-macos.png")
  | |             ------------------------------- expected because of this
5 | |         } else {
6 | |             include_bytes!("../assets/icon.png")
  | |             ^^^^^^^^^^^^^^^^^^^^^^^^^ expected an array with a fixed size of 63249 elements, found one with 471 elements
7 | |         };
  | |_________- `if` and `else` have incompatible types
  |
  = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)

虽然我知道为什么会发生这个错误,但有没有比下面列出的代码更好的方法来解决这个问题?

let (icon_rgba, icon_width, icon_height) = {
        if cfg!(target_os = "macos") {
            let icon = include_bytes!("../assets/icon-macos.png");
            let image = image::load_from_memory(icon)
                .expect("Failed to open icon path")
                .into_rgba8();
            let (width, height) = image.dimensions();
            let rgba = image.into_raw();
            (rgba, width, height)
        } else {
            let icon = include_bytes!("../assets/icon.png");
            let image = image::load_from_memory(icon)
                .expect("Failed to open icon path")
                .into_rgba8();
            let (width, height) = image.dimensions();
            let rgba = image.into_raw();
            (rgba, width, height)
        };
    };
2exbekwf

2exbekwf1#

即使cfg在类型检查之前被计算,你的代码也不能编译。这是因为尽管编译器将cfg!(...)评估为truefalse,但它不会评估if块。
要让编译器有条件地只发出一个分支,你必须使用#[cfg(...)]属性:

let (icon_rgba, icon_width, icon_height) = {

    #[cfg!(target_os = "macos")]
    let icon = include_bytes!("../assets/icon-macos.png");
    #[cfg!(not(target_os = "macos"))]
    let icon = include_bytes!("../assets/icon.png");

    let image = image::load_from_memory(icon)
        .expect("Failed to open icon path")
        .into_rgba8();
    let (width, height) = image.dimensions();
    let rgba = image.into_raw();
    (rgba, width, height)
};
bf1o4zei

bf1o4zei2#

问题是编译器将&[u8; <size_of_the_macos_png>]推断为image的类型,因为这是第一个分支的include_bytes!()解析的类型,当它检查第二个分支时,它看到的是&[u8; <size_of_the_other_png>],但两种类型都不能强制转换为另一种类型,因此编译器抛出错误。
幸运的是,你可以给予编译器一个类型提示,让它使用切片,它很乐意强制使用切片:

let (icon_rgba, icon_width, icon_height) = {
        let icon: &[u8] = if cfg!(target_os = "macos") {
            include_bytes!("../assets/icon-macos.png")
        } else {
            include_bytes!("../assets/icon.png")
        };
        let image = image::load_from_memory(icon)
            .expect("Failed to open icon path")
            .into_rgba8();
        let (width, height) = image.dimensions();
        let rgba = image.into_raw();
        (rgba, width, height)
    };

您也可以使用as &[u8].as_slice()中的一个(或两个)include_bytes!()调用,但它更详细,而且有点不对称(甚至更详细),所以我更喜欢绑定上的类型提示。

相关问题