路径

路径 是由一个或多个路径段从 逻辑上 由命名空间 限定符(::) 分隔的序列。 如果路径只包含一个段,则引用局部作用域中的 条目变量 。如果路径有多个段,则总是引用一个条目。

以下是由标识符段组成的简单路径的两个示例:

x;
x::y::z;

路径的类型

简单路径

语法
简单路径 :
   ::? 简单路径片段 (:: 简单路径片段)*

简单路径片段 :
   标识符 | 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() {}
}
}

路径表达式

语法
表达式中路径 :
   ::? 路径表达式片段 (:: 路径表达式片段)*

路径表达式片段 :
   路径ID片段 (:: 泛型参数组)?

路径ID片段 :
   标识符 | super | self | Self | crate | $crate

泛型参数组 :
      < >
   | < ( 泛型参数 , )* 泛型参数 ,? >

泛型参数 :
   生命周期 | 类型 | 泛型参数组常量 | 泛型参数组绑定

泛型参数组常量 :
      块表达式
   | 字面值表达式
   | - 字面值表达式
   | 简单路径片段

泛型参数组绑定 :
   标识符= 类型

路径允许指定带有泛型参数表达式的路径。可在表达式和模式的各个位置使用。

在泛型参数的左括号 < 前面需要添加 :: 标记以避免与小于号操作符产生歧义。这通常被称为 "鱼形" 语法。

#![allow(unused)]
fn main() {
(0..10).collect::<Vec<_>>();
Vec::<u8>::with_capacity(1024);
}

泛型参数的顺序是受限的,首先是生命周期参数,然后是类型参数,然后是常量参数,最后是相等性约束。

常量参数必须用花括号括起来,除非是字面量或简单路径段。

对于 impl Trait 类型对应的合成类型参数是隐式的,不能显式地指定。

限定路径

语法
表达式中的限定路径 :
   限定路径类型 (:: 路径表达式片段)+

限定路径类型 :
   < Type (as 类型路径)? >

类型中限定路径 :
   限定路径类型 (:: 类型路径片段)+

完全限定路径用于在 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();  // 调用内部 impl.
<S as T1>::f();  // 调用 T1 trait 函数。
<S as T2>::f();  // 调用 T2 trait 函数。
}

类型中路径

语法
类型路径 :
   ::? 类型路径片段 (:: 类型路径片段)*

类型路径片段 :
   类型ID片段 ::? (泛型参数 | 类型路径Fn)?

类型路径Fn :
( 类型路径Fn输入组? ) (-> 类型)?

类型路径Fn输入组 :
类型 (, 类型)* ,?

类型路径在类型定义、trait 约束、类型参数约束和限定路径中使用。

虽然 :: token 在泛型参数之前是允许的,但不是必须的,因为与在 表达式中路径 的情况不同,这里没有歧义。

#![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 root" 开始解析 (在 2018 版本中是 crate::) ,其中包括各种不同的条目,包括外部 crate、默认的 crate (如 stdcore) 以及 crate 顶层条目 (包括 use 导入) 。

从 2018 版本开始,以 :: 开头的路径从 extern prelude 中的 crate 解析。也就是说,符号必须跟随 crate 的名称。

#![allow(unused)]
fn main() {
pub fn foo() {
    // 在 2018 版中,这通过 extern 预导模块访问 std。
    // 在 2015 版中,这通过 crate root 访问 std。
    let now = ::std::time::Instant::now();
    println!("{:?}", now);
}
}
// 2015 版
mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        ::a::foo(); // 调用 `a` 的 foo 函数
        // 在 Rust 2018 中, `::a` 将被解释为 crate `a` 。
    }
}
fn main() {}

self

self 相对于当前模块,只能作为路径的第一个段,不能在前面加上 ::

fn foo() {}
fn bar() {
    self::foo();
}
fn main() {}

Self

Self (注意大写) 用于在 traits实现 中引用实现类型本身。

Self 只能作为第一个段,不能有前导 ::

#![allow(unused)]
fn main() {
trait T {
    type Item;
    const C: i32;
    // `Self` 将是任何实现 `T` 的类型。
    fn new() -> Self;
    // `Self::Item` 将是实现中的类型别名。
    fn f(&self) -> Self::Item;
}
struct S;
impl T for S {
    type Item = i32;
    const C: i32 = 9;
    fn new() -> Self {           // `Self` 是类型 `S`。
        S
    }
    fn f(&self) -> Self::Item {  // `Self::Item` 是类型 `i32`。
        Self::C                  // `Self::C` 是常量值 `9`。
    }
}
}

super

super 在路径中解析为父模块。只能在路径的前导段中使用,可在起始 self 段之后。

mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        super::a::foo(); // call a's foo function
    }
}
fn main() {}

super 可以在第一个 superself 之后重复使用,以引用祖先模块。

mod a {
    fn foo() {}

    mod b {
        mod c {
            fn foo() {
                super::super::foo(); // 调用 a's foo 函数
                self::super::super::foo(); // 调用 a's foo 函数
            }
        }
    }
}
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 中的位置。

// 注释显示了条目的规范路径。

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() {}