Rust doctest 内 `extern crate self as crate_name` 报 E0425
Rustdoc 执行文档测试时遵循默认包装规则:若代码块未显式定义fn main,会自动将整块代码包裹到自动生成的main函数内部。
此规则下,编写的extern crate self as crate_name声明、Member结构体都会成为main函数的局部项;而::crate_name::Member是从crate根开始查找的绝对路径,无法定位函数内部的局部定义,因此触发E0425错误。普通编写的代码中,声明天然处于crate根或模块层级,因此不会出现该问题。
方案一:显式定义fn main,保留原有写法
只要代码块中存在显式声明的fn main,Rustdoc就不会执行自动包裹逻辑,所有顶层声明都会处于测试crate的根层级,extern crate self设置的别名可正常映射到当前测试crate根。
示例代码:
/// ```rust /// extern crate self as crate_name; /// pub struct Member; /// /// fn main() { /// // 宏展开生成的全限定路径可正常解析 /// let _ = ::crate_name::Member; /// } /// ``` fn example() {}
适用场景:需要模拟完整crate根路径、测试逻辑需要实际执行的场景,和普通crate内的代码写法完全一致。
方案二:定义同名模块模拟crate结构(推荐过程宏测试使用)
全限定路径::crate_name的本质是从当前crate根查找名为crate_name的顶层项,无需依赖extern crate self特性。直接定义同名顶层模块,将所有需要模拟的类型、特征放入对应模块即可。
示例代码:
/// ```rust /// // 按照目标crate的实际模块结构定义模拟内容 /// mod crate_name { /// pub struct Member; /// } /// /// fn main() { /// let _ = ::crate_name::Member; /// } /// ``` fn example() {}
该方案不受文档测试包装规则、Rust edition版本影响,路径解析逻辑和真实外部crate的导入行为完全一致;可按需模拟目标crate的嵌套模块结构,无需暴露多余定义,适配过程宏的编译验证需求。
方案三:添加no_main标记禁止自动包装
给文档测试代码块添加no_main属性后,Rustdoc不会自动生成或包裹main函数,会将代码直接编译为库crate,所有顶层声明天然处于crate根层级,无需手写main函数。
示例代码:
/// ```rust,no_main /// extern crate self as crate_name; /// pub struct Member; /// /// // 仅验证宏展开与路径解析是否正常,无需实际执行 /// fn test_path_resolve() { /// let _ = ::crate_name::Member; /// } /// ``` fn example() {}
适用场景:仅需验证宏展开、路径解析的编译合法性,不需要运行测试逻辑的场景,可省略冗余的main函数。
- 若过程宏生成的路径包含多层嵌套(如
::crate_name::utils::Handle),按照目标crate的真实模块层级定义即可,上述三种方案均支持。 - Rustdoc默认会自动注入当前文档所属crate的导入声明,与自定义crate别名、模拟模块互不冲突。
内容的提问来源于stack exchange,提问作者Drew

