Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Пути

Путь — это последовательность из одного или более сегментов пути, разделённых токенами ::. Пути используются для ссылки на элементы, значения, типы, макросы и атрибуты.

Два примера простых путей, состоящих только из идентификаторных сегментов:

x;
x::y::z;

Типы путей

Простые пути

Syntax
SimplePath
    ::? SimplePathSegment ( :: SimplePathSegment )*

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

Пути в выражениях

Syntax
PathInExpression
    ::? PathExprSegment ( :: PathExprSegment )*

PathExprSegment
    PathIdentSegment ( :: GenericArgs )?

PathIdentSegment
    IDENTIFIER | super | self | Self | crate | $crate

GenericArgs
      < >
    | < ( GenericArg , )* GenericArg ,? >

GenericArg
    Lifetime | Type | GenericArgsConst | GenericArgsBinding | GenericArgsBounds

GenericArgsConst
      BlockExpression
    | LiteralExpression
    | - LiteralExpression
    | SimplePathSegment

GenericArgsBinding
    IDENTIFIER GenericArgs? = Type

GenericArgsBounds
    IDENTIFIER GenericArgs? : TypeParamBounds

Пути в выражениях позволяют указывать пути с обобщёнными аргументами. Они используются в различных местах в выражениях и образцах.

Токен :: требуется перед открывающим < для обобщённых аргументов, чтобы избежать неоднозначности с оператором “меньше”. Это в просторечии известно как синтаксис “турбо-рыбы”.

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

Порядок обобщённых аргументов ограничен: сначала аргументы времени жизни, затем аргументы типов, затем аргументы констант, затем ограничения равенства.

Аргументы констант должны быть окружены фигурными скобками, если они не являются литералом, выводимой константой или путём из одного сегмента. Выводимая константа не может быть окружена фигурными скобками.

#![allow(unused)]
fn main() {
mod m {
    pub const C: usize = 1;
}
const C: usize = m::C;
fn f<const N: usize>() -> [u8; N] { [0; N] }

let _ = f::<1>(); // Литерал.
let _: [_; 1] = f::<_>(); // Выводимая константа.
let _: [_; 1] = f::<(((_)))>(); // Выводимая константа.
let _ = f::<C>(); // Путь из одного сегмента.
let _ = f::<{ m::C }>(); // Путь из нескольких сегментов должен быть в скобках.
}
#![allow(unused)]
fn main() {
fn f<const N: usize>() -> [u8; N] { [0; _] }
let _: [_; 1] = f::<{ _ }>();
//                    ^ ОШИБКА: `_` не разрешён здесь
}

Note

В списке обобщённых аргументов выводимая константа разбирается как выводимый тип, но затем семантически обрабатывается как отдельный вид аргумента обобщённой константы.

Синтетические параметры типа, соответствующие типам impl 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();  // Вызывает собственную реализацию.
<S as T1>::f();  // Вызывает функцию трейта T1.
<S as T2>::f();  // Вызывает функцию трейта T2.
}

Пути в типах

Пути типов используются в определениях типов, ограничениях трейтов, ограничениях параметров типа и квалифицированных путях.

Хотя токен :: разрешён перед обобщёнными аргументами, он не требуется, поскольку нет неоднозначности, как в PathInExpression.

#![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>;
}

Квалификаторы путей

Пути могут обозначаться различными ведущими квалификаторами для изменения смысла того, как они разрешаются.

::

Пути, начинающиеся с ::, считаются глобальными путями, где сегменты пути начинают разрешаться из места, которое различается в зависимости от редакции. Каждый идентификатор в пути должен разрешаться в элемент.

2018 Edition differences

В редакции 2015 идентификаторы разрешаются из “корня крейта” (crate:: в редакции 2018), который содержит различные элементы, включая внешние крейты, крейты по умолчанию, такие как std или core, и элементы на верхнем уровне крейта (включая импорты use).

Начиная с редакции 2018, пути, начинающиеся с ::, разрешаются из крейтов во внешней прелюдии. То есть за ними должно следовать имя крейта.

#![allow(unused)]
fn main() {
pub fn foo() {
    // В редакции 2018 это обращается к `std` через внешнюю прелюдию.
    // В редакции 2015 это обращается к `std` через корень крейта.
    let now = ::std::time::Instant::now();
    println!("{:?}", now);
}
}
// Редакция 2015
mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        ::a::foo(); // вызывает функцию foo из `a`
        // В Rust 2018 `::a` интерпретировался бы как крейт `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” используется для ссылки на текущий тип, который реализуется или определяется. Он может использоваться в следующих ситуациях:

  • В определении трейта он ссылается на тип, реализующий трейт.

Область видимости Self ведёт себя аналогично обобщённому параметру; см. раздел область видимости Self для подробностей.

Self может использоваться только как первый сегмент, без предшествующего ::.

Путь Self не может включать обобщённые аргументы (как в Self::<i32>).

#![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`.
    }
}

// `Self` находится в области видимости внутри обобщённых параметров определения трейта,
// для ссылки на определяемый тип.
trait Add<Rhs = Self> {
    type Output;
    // `Self` также может ссылаться на ассоциированные элементы
    // реализуемого типа.
    fn add(self, rhs: Rhs) -> Self::Output;
}

struct NonEmptyList<T> {
    head: T,
    // Структура может ссылаться на себя (пока это не
    // бесконечная рекурсия).
    tail: Option<Box<Self>>,
}
}

super

super в пути разрешается в родительский модуль.

Он может использоваться только в ведущих сегментах пути, возможно после начального сегмента self.

mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        super::a::foo(); // вызывает функцию foo из a
    }
}
fn main() {}

super может повторяться несколько раз после первого super или self для ссылки на модули-предки.

mod a {
    fn foo() {}

    mod b {
        mod c {
            fn foo() {
                super::super::foo(); // вызывает функцию foo из a
                self::super::super::foo(); // вызывает функцию foo из a
            }
        }
    }
}
fn main() {}

crate

crate разрешает путь относительно текущего крейта.

crate может использоваться только как первый сегмент, без предшествующего ::.

fn foo() {}
mod a {
    fn bar() {
        crate::foo();
    }
}
fn main() {}

$crate

$crate используется только внутри транскриберов макросов и может использоваться только как первый сегмент, без предшествующего ::.

$crate развернётся в путь для доступа к элементам из верхнего уровня крейта, где определён макрос, независимо от того, в каком крейте макрос вызывается.

pub fn increment(x: u32) -> u32 {
    x + 1
}

#[macro_export]
macro_rules! inc {
    ($x:expr) => ( $crate::increment($x) )
}
fn main() { }

Канонические пути

Элементы, определённые в модуле или реализации, имеют канонический путь, который соответствует месту внутри его крейта, где он определён.

Все другие пути к этим элементам являются псевдонимами.

Канонический путь определяется как префикс пути, к которому добавлен сегмент пути, который определяет сам элемент.

Реализации и use-объявления не имеют канонических путей, хотя элементы, которые определяют реализации, имеют их. Элементы, определённые в блочных выражениях, не имеют канонических путей. Элементы, определённые в модуле, который не имеет канонического пути, не имеют канонического пути. Ассоциированные элементы, определённые в реализации, которая ссылается на элемент без канонического пути, например, как на реализуемый тип, реализуемый трейт, параметр типа или ограничение на параметр типа, не имеют канонических путей.

Префикс пути для модулей — это канонический путь к этому модулю.

Для простых реализаций это канонический путь элемента, который реализуется, окружённый угловыми (<>) скобками.

Для реализаций трейтов это канонический путь элемента, который реализуется, за которым следует as, за которым следует канонический путь к трейту, всё окружённое угловыми (<>) скобками.

Канонический путь имеет смысл только в пределах данного крейта. Нет глобального пространства имён между крейтами; канонический путь элемента лишь идентифицирует его в пределах крейта.

// Комментарии показывают канонический путь элемента.

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