You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无struct的Rust模块声明与使用:重复声明是否必要?

Rust模块声明疑问:为何需要两次pub mod img_util?

我编写了一个不含struct的Rust模块,当前代码结构如下:

img_util.rs:

pub mod img_util {
    use image::{ImageBuffer, Pixel};
    use std::{fs::File, io::BufWriter};

    fn get_color_type<P>() -> Result<png::ColorType, std::io::Error>
    where
        P: Pixel<Subpixel = u8>,
    {
        match <P as Pixel>::CHANNEL_COUNT {
            4 => Ok(png::ColorType::Rgba),
            3 => Ok(png::ColorType::Rgb),
            _ => Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                "Incorrect color channel count / format.",
            )),
        }
    }

    fn get_dpi_header_data(dpi: u32) -> Vec<u8> {
        let dpm = 39.370079 * dpi as f32;
        let rounded_dpm = dpm.round() as u32;

        let mut data: Vec<u8> = Vec::new();
        data.extend_from_slice(&rounded_dpm.to_be_bytes()); // Pixels per unit in X-direction.
        data.extend_from_slice(&rounded_dpm.to_be_bytes()); // Pixels per unit in Y-direction.

        data.push(1); // Indicate that meters are used as unit.
        data
    }

    pub fn save_png_with_dpi<P>(
        input_img: &ImageBuffer<P, Vec<u8>>,
        output_img: File,
        dpi: u32,
    ) -> Result<(), std::io::Error>
    where
        P: Pixel<Subpixel = u8>,
    {
        let w = &mut BufWriter::new(output_img);
        let (width, height) = input_img.dimensions();
        let mut encoder = png::Encoder::new(w, width, height);

        encoder.set_color(get_color_type::<P>()?);
        encoder.set_depth(png::BitDepth::Eight);
        encoder.set_compression(png::Compression::Best);

        let data = get_dpi_header_data(dpi);
        let mut writer = encoder.write_header()?;

        writer.write_chunk(png::chunk::pHYs, data.as_slice())?;
        writer.write_image_data(input_img)?;
        Ok(())
    }
}

lib.rs:

pub mod img_util;

main.rs:

use visual_center::img_util::img_util;

img_util::save_png_with_dpi(
    // arguments
).unwrap();

目前模块可以正常使用,但我困惑为何需要两次声明pub mod img_util(一次在img_util.rs中,一次在lib.rs中),想询问这是否是声明和使用无struct模块的唯一方式?


这不是必须的,你现在的写法其实是嵌套了两层模块,完全可以简化:

问题根源

你在img_util.rs里写了pub mod img_util { ... },相当于在这个文件内部又定义了一个子模块;而lib.rs里的pub mod img_util;是把整个img_util.rs作为 crate 的一级模块引入。这就导致你的函数实际位于visual_center::img_util::img_util路径下,所以使用时需要两层引用。

正确的简化写法

直接去掉img_util.rs里的外层pub mod img_util,把内容平放在文件里:

修改后的img_util.rs:

use image::{ImageBuffer, Pixel};
use std::{fs::File, io::BufWriter};

fn get_color_type<P>() -> Result<png::ColorType, std::io::Error>
where
    P: Pixel<Subpixel = u8>,
{
    match <P as Pixel>::CHANNEL_COUNT {
        4 => Ok(png::ColorType::Rgba),
        3 => Ok(png::ColorType::Rgb),
        _ => Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "Incorrect color channel count / format.",
        )),
    }
}

fn get_dpi_header_data(dpi: u32) -> Vec<u8> {
    let dpm = 39.370079 * dpi as f32;
    let rounded_dpm = dpm.round() as u32;

    let mut data: Vec<u8> = Vec::new();
    data.extend_from_slice(&rounded_dpm.to_be_bytes()); // Pixels per unit in X-direction.
    data.extend_from_slice(&rounded_dpm.to_be_bytes()); // Pixels per unit in Y-direction.

    data.push(1); // Indicate that meters are used as unit.
    data
}

pub fn save_png_with_dpi<P>(
    input_img: &ImageBuffer<P, Vec<u8>>,
    output_img: File,
    dpi: u32,
) -> Result<(), std::io::Error>
where
    P: Pixel<Subpixel = u8>,
{
    let w = &mut BufWriter::new(output_img);
    let (width, height) = input_img.dimensions();
    let mut encoder = png::Encoder::new(w, width, height);

    encoder.set_color(get_color_type::<P>()?);
    encoder.set_depth(png::BitDepth::Eight);
    encoder.set_compression(png::Compression::Best);

    let data = get_dpi_header_data(dpi);
    let mut writer = encoder.write_header()?;

    writer.write_chunk(png::chunk::pHYs, data.as_slice())?;
    writer.write_image_data(input_img)?;
    Ok(())
}

lib.rs保持不变:

pub mod img_util;

修改后的main.rs:

// 直接引用一级模块即可
use visual_center::img_util;

img_util::save_png_with_dpi(
    // arguments
).unwrap();
// 或者直接使用完整路径,不需要use
// visual_center::img_util::save_png_with_dpi(...).unwrap();

总结

这种平级写法才是Rust模块的常规用法,不管模块里有没有struct,都不需要嵌套声明。你之前的两次pub mod是误加了内层模块定义,属于冗余写法。

内容的提问来源于stack exchange,提问作者wyc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 01:09:58