路径
路径 是由一个或多个路径段组成的序列,这些路径段由 ::
标记分隔。路径用于引用 条目、值、类型、宏 和 属性。
以下是由标识符段组成的简单路径的两个示例
x;
x::y::z;
路径的类型
简单路径
语法
SimplePath :
::
? 简单路径段 (::
简单路径段)*SimplePathSegment :
标识符 |super
|self
|crate
|$crate
简单路径用于 可见性 标记、属性、宏 和 use
条目。例如
#![allow(unused)] fn main() { use std::io::{self, Write}; mod m { #[clippy::cyclomatic_complexity = "0"] pub (in super) fn f1() {} } }
表达式中的路径
语法
PathInExpression :
::
? 路径表达式段 (::
路径表达式段)*PathExprSegment :
路径标识符段 (::
泛型参数)?PathIdentSegment :
标识符 |super
|self
|Self
|crate
|$crate
GenericArgs :
<
>
|<
( 泛型实参,
)* 泛型实参,
?>
GenericArg :
生命周期 | 类型 | GenericArgsConst | GenericArgsBinding | GenericArgsBoundsGenericArgsConst :
BlockExpression
| 字面量表达式
|-
字面量表达式
| 简单路径段
表达式中的路径允许指定带有泛型参数的路径。它们在 表达式 和 模式 中的各种地方使用。
在泛型参数的开头的 <
之前需要 ::
标记,以避免与小于运算符混淆。这在口语上被称为“turbofish”语法。
#![allow(unused)] fn main() { (0..10).collect::<Vec<_>>(); Vec::<u8>::with_capacity(1024); }
泛型参数的顺序限制为:生命周期参数,然后是类型参数,然后是常量参数,最后是相等性约束。
常量参数必须用花括号括起来,除非它们是 字面量 或单段路径。
对应于 impl Trait
类型的合成类型参数是隐式的,并且不能显式指定。
限定路径
语法
QualifiedPathInExpression :
限定路径类型 (::
路径表达式段)+QualifiedPathType :
<
类型 (as
类型路径)?>
QualifiedPathInType :
限定路径类型 (::
类型路径段)+
完全限定路径允许消除 trait 实现 的路径歧义,并允许指定 规范路径。当在类型规范中使用时,它支持使用下面指定的类型语法。
#![allow(unused)] fn main() { struct S; impl S { fn f() { println!("S"); } } trait T1 { fn f() { println!("T1 f"); } } impl T1 for S {} trait T2 { fn f() { println!("T2 f"); } } impl T2 for S {} S::f(); // Calls the inherent impl. <S as T1>::f(); // Calls the T1 trait function. <S as T2>::f(); // Calls the T2 trait function. }
类型中的路径
语法
TypePath :
::
? 类型路径段 (::
类型路径段)*TypePathSegment :
路径标识符段 (::
? (泛型参数 | 类型路径函数))?TypePathFn :
(
类型路径函数输入?)
(->
无边界类型)?
类型路径在类型定义、trait 边界、类型参数边界和限定路径中使用。
尽管在泛型参数之前允许使用 ::
标记,但这不是必需的,因为不像在 表达式路径 中那样存在歧义。
#![allow(unused)] fn main() { mod ops { pub struct Range<T> {f1: T} pub trait Index<T> {} pub struct Example<'a> {f1: &'a i32} } struct S; impl ops::Index<ops::Range<usize>> for S { /*...*/ } fn i<'a>() -> impl Iterator<Item = ops::Example<'a>> { // ... const EXAMPLE: Vec<ops::Example<'static>> = Vec::new(); EXAMPLE.into_iter() } type G = std::boxed::Box<dyn std::ops::FnOnce(isize) -> isize>; }
路径限定符
路径可以使用各种前导限定符来表示,以更改其解析方式的含义。
::
以 ::
开头的路径被认为是全局路径,其中路径的段开始从一个位置解析,该位置因版本而异。路径中的每个标识符都必须解析为一个条目。
版本差异:在 2015 版本中,标识符从“crate 根”(2018 版本中的
crate::
)解析,其中包含各种不同的条目,包括外部 crate、默认 crate(例如std
或core
)以及 crate 顶层的条目(包括use
导入)。从 2018 版本开始,以
::
开头的路径从 外部 prelude 中的 crate 解析。也就是说,它们后面必须跟 crate 的名称。
#![allow(unused)] fn main() { pub fn foo() { // In the 2018 edition, this accesses `std` via the extern prelude. // In the 2015 edition, this accesses `std` via the crate root. let now = ::std::time::Instant::now(); println!("{:?}", now); } }
// 2015 Edition mod a { pub fn foo() {} } mod b { pub fn foo() { ::a::foo(); // call `a`'s foo function // In Rust 2018, `::a` would be interpreted as the crate `a`. } } fn main() {}
self
self
解析相对于当前模块的路径。self
只能用作第一个段,前面不能有 ::
。
在方法体中,由单个 self
段组成的路径解析为该方法的 self 参数。
fn foo() {} fn bar() { self::foo(); } struct S(bool); impl S { fn baz(self) { self.0; } } fn main() {}
Self
Self
,首字母大写“S”,用于指代当前正在实现或定义的类型。它可以在以下情况中使用
- 在 trait 定义中,它指代实现该 trait 的类型。
- 在 实现 中,它指代正在实现的类型。当实现元组或单元 struct 时,它也指代 值命名空间 中的构造器。
- 在 struct、enumeration 或 union 的定义中,它指代正在定义的类型。定义不允许无限递归(必须有一个间接层)。
Self
的作用域行为类似于泛型参数;有关更多详细信息,请参阅 Self
作用域 部分。
Self
只能用作第一个段,前面不能有 ::
。Self
路径不能包含泛型参数(如 Self::<i32>
)。
#![allow(unused)] fn main() { trait T { type Item; const C: i32; // `Self` will be whatever type that implements `T`. fn new() -> Self; // `Self::Item` will be the type alias in the implementation. fn f(&self) -> Self::Item; } struct S; impl T for S { type Item = i32; const C: i32 = 9; fn new() -> Self { // `Self` is the type `S`. S } fn f(&self) -> Self::Item { // `Self::Item` is the type `i32`. Self::C // `Self::C` is the constant value `9`. } } // `Self` is in scope within the generics of a trait definition, // to refer to the type being defined. trait Add<Rhs = Self> { type Output; // `Self` can also reference associated items of the // type being implemented. fn add(self, rhs: Rhs) -> Self::Output; } struct NonEmptyList<T> { head: T, // A struct can reference itself (as long as it is not // infinitely recursive). tail: Option<Box<Self>>, } }
super
路径中的 super
解析为父模块。它只能在路径的前导段中使用,可能在初始 self
段之后。
mod a { pub fn foo() {} } mod b { pub fn foo() { super::a::foo(); // call a's foo function } } fn main() {}
在第一个 super
或 self
之后,super
可以重复多次以引用祖先模块。
mod a { fn foo() {} mod b { mod c { fn foo() { super::super::foo(); // call a's foo function self::super::super::foo(); // call a's foo function } } } } fn main() {}
crate
crate
解析相对于当前 crate 的路径。crate
只能用作第一个段,前面不能有 ::
。
fn foo() {} mod a { fn bar() { crate::foo(); } } fn main() {}
$crate
$crate
仅在 宏转录器 中使用,并且只能用作第一个段,前面不能有 ::
。$crate
将扩展为访问定义宏的 crate 顶层条目的路径,无论宏在哪个 crate 中调用。
pub fn increment(x: u32) -> u32 { x + 1 } #[macro_export] macro_rules! inc { ($x:expr) => ( $crate::increment($x) ) } fn main() { }
规范路径
在模块或实现中定义的条目具有规范路径,该路径对应于其在 crate 内定义的位置。所有其他指向这些条目的路径都是别名。规范路径定义为路径前缀,后跟条目本身定义的路径段。
实现 和 use 声明 没有规范路径,但实现定义的条目具有规范路径。在块表达式中定义的条目没有规范路径。在没有规范路径的模块中定义的条目没有规范路径。在引用没有规范路径的条目的实现中定义的关联条目,例如作为实现类型、正在实现的 trait、类型参数或类型参数的边界,没有规范路径。
模块的路径前缀是该模块的规范路径。对于裸实现,它是被实现的条目的规范路径,用 尖括号 (<>
) 括起来。对于 trait 实现,它是被实现的条目的规范路径,后跟 as
,然后是 trait 的规范路径,所有这些都用 尖括号 (<>
) 括起来。
规范路径仅在给定的 crate 中有意义。crate 之间没有全局命名空间;条目的规范路径仅在 crate 内标识它。
// Comments show the canonical path of the item. mod a { // crate::a pub struct Struct; // crate::a::Struct pub trait Trait { // crate::a::Trait fn f(&self); // crate::a::Trait::f } impl Trait for Struct { fn f(&self) {} // <crate::a::Struct as crate::a::Trait>::f } impl Struct { fn g(&self) {} // <crate::a::Struct>::g } } mod without { // crate::without fn canonicals() { // crate::without::canonicals struct OtherStruct; // None trait OtherTrait { // None fn g(&self); // None } impl OtherTrait for OtherStruct { fn g(&self) {} // None } impl OtherTrait for crate::a::Struct { fn g(&self) {} // None } impl crate::a::Trait for OtherStruct { fn f(&self) {} // None } } } fn main() {}