在使用单独的模块时,未声明类型或模块 `std` 的使用方法。

29

我有以下代码:

pub mod a {
    #[test]
    pub fn test() {
        println!("{:?}", std::fs::remove_file("Somefilehere"));
    }
}

我编译这段代码时出现了错误:

error[E0433]: failed to resolve. Use of undeclared type or module `std`
 --> src/main.rs:4:24
  |
4 |         println!("{}", std::fs::remove_file("Somefilehere"));
  |                        ^^^ Use of undeclared type or module `std`

不过,移除内部模块并将其包含的代码单独编译却可以正常工作:

#[test]
pub fn test() {
    println!("{:?}", std::fs::remove_file("Somefilehere"));
}

我在这里漏掉了什么?如果模块在单独的文件中,我会得到相同的错误:

main.rs

pub mod a;

a.rs

#[test]
pub fn test() {
    println!("{:?}", std::fs::remove_file("Somefilehere"));
}
2个回答

52

默认情况下,编译器在crate根(即您传递给rustc的文件)开头插入extern crate std;。此语句的效果是将名称std添加到crate的根命名空间中,并将其与包含std crate公共内容的模块相关联。

然而,在子模块中,std不会自动添加到模块的命名空间中。这就是为什么编译器无法在模块中解析std(或以std ::开头的任何内容)的原因。

有许多方法可以解决这个问题。首先,您可以在模块中添加use std;,使名称std指向该模块内的根std。请注意,在use语句中,路径被视为绝对路径(或“相对于crate的根命名空间”),而在其他地方,路径被视为相对于当前命名空间(无论是模块、函数等)。

pub mod a {
    use std;

    #[test]
    pub fn test() {
        println!("{:?}", std::fs::remove_file("Somefilehere"));
    }
}

您还可以使用use语句导入更具体的项目。例如,您可以编写use std::fs::remove_file;。这样可以避免在模块中键入整个路径来引用remove_file,而直接使用remove_file的名称:

pub mod a {
    use std::fs::remove_file;

    #[test]
    pub fn test() {
        println!("{:?}", remove_file("Somefilehere")));
    }
}

最后,您可以通过在路径前加上::来避免使用use,以请求编译器从crate的根命名空间解析路径(即将路径转换为绝对路径)。

pub mod a {
    #[test]
    pub fn test() {
        println!("{:?}", ::std::fs::remove_file("Somefilehere"));
    }
}

推荐的做法是直接导入类型(结构体、枚举等)(例如 use std::rc::Rc;,然后使用路径 Rc),但是通过父模块导入函数(例如 use std::io::fs;,然后使用路径 fs::remove_file)。

pub mod a {
    use std::fs;

    #[test]
    pub fn test() {
        println!("{:?}", fs::remove_file("Somefilehere"));
    }
}

小提示:您还可以在路径开头写上self::,使其相对于当前模块。这在use语句中更常用,因为其他路径已经是相对的(虽然它们是相对于当前命名空间的),而self::始终相对于包含模块


谢谢你的建议!在编程实践中,使用路径之前是否被认为是更好的做法,而不是通过路径(std::io::some::other::path)进行操作? - luke
1
我也是一个 Rust 新手,所以我仍然不清楚什么是最佳实践。我会建议您选择您感到最舒适的特定级别 - 您也可以只使用 use std::io::fs,然后调用例如 fs::unlink - Renato Zannon

2

现在,std可以直接从任何地方访问,因此您展示的代码可以像预期的那样编译。

此外,在Rust 2018版中不再需要extern crate。将依赖项添加到Cargo.toml使创建名称直接可用作顶级标识符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接