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

Объявления use

Syntax
UseDeclarationuse UseTree ;

UseTree
      ( SimplePath? :: )? *
    | ( SimplePath? :: )? { ( UseTree ( , UseTree )* ,? )? }
    | SimplePath ( as ( IDENTIFIER | _ ) )?

Объявление use создаёт одну или несколько локальных привязок имён, синонимичных некоторому другому пути. Обычно объявление use используется для сокращения пути, требуемого для ссылки на элемент модуля. Эти объявления могут появляться в модулях и блоках, обычно вверху. Объявление use также иногда называется импортом, или, если оно публичное, реэкспортом.

Объявления use поддерживают ряд удобных сокращений:

  • Одновременная привязка списка путей с общим префиксом с использованием синтаксиса фигурных скобок use a::b::{c, d, e::f, g::h::i};
  • Одновременная привязка списка путей с общим префиксом и их общего родительского модуля с использованием ключевого слова self, например use a::b::{self, c, d::e};
  • Перепривязка целевого имени как нового локального имени с использованием синтаксиса use p::q::r as x;. Это также может использоваться с последними двумя функциями: use a::b::{self as ab, c as abc}.
  • Привязка всех путей, соответствующих заданному префиксу, с использованием синтаксиса подстановочного знака звездочки use a::b::*;.
  • Вложенные группы предыдущих функций несколько раз, такие как use a::b::{self as ab, c, d::{*, e::f}};

Пример объявлений use:

use std::collections::hash_map::{self, HashMap};

fn foo<T>(_: T){}
fn bar(map1: HashMap<String, usize>, map2: hash_map::HashMap<String, usize>){}

fn main() {
    // объявления use также могут существовать внутри функций
    use std::option::Option::{Some, None};

    // Эквивалентно 'foo(vec![std::option::Option::Some(1.0f64),
    // std::option::Option::None]);'
    foo(vec![Some(1.0f64), None]);

    // И `hash_map`, и `HashMap` находятся в области видимости.
    let map1 = HashMap::new();
    let map2 = hash_map::HashMap::new();
    bar(map1, map2);
}

Видимость use

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

Если последовательность таких перенаправлений образует цикл или не может быть разрешена однозначно, они представляют ошибку времени компиляции.

Пример реэкспорта:

mod quux {
    pub use self::foo::{bar, baz};
    pub mod foo {
        pub fn bar() {}
        pub fn baz() {}
    }
}

fn main() {
    quux::bar();
    quux::baz();
}

В этом примере модуль quux реэкспортирует два публичных имени, определённых в foo.

Пути use

Пути, которые разрешены в элементе use, следуют грамматике SimplePath и похожи на пути, которые могут использоваться в выражении. Они могут создавать привязки для:

Они не могут импортировать ассоциированные элементы, обобщённые параметры, локальные переменные, пути с Self или инструментальные атрибуты. Дополнительные ограничения описаны ниже.

use создаст привязки для всех пространств имён из импортированных сущностей, за исключением того, что импорт self будет импортировать только из пространства имён типов (как описано ниже). Например, следующее иллюстрирует создание привязок для одного и того же имени в двух пространствах имён:

#![allow(unused)]
fn main() {
mod stuff {
    pub struct Foo(pub i32);
}

// Импортирует тип `Foo` и конструктор `Foo`.
use stuff::Foo;

fn example() {
    let ctor = Foo; // Использует `Foo` из пространства имён значений.
    let x: Foo = ctor(123); // Использует `Foo` из пространства имён типов.
}
}

2018 Edition differences

В редакции 2015 пути use относительны к корню крейта. Например:

mod foo {
    pub mod example { pub mod iter {} }
    pub mod baz { pub fn foobaz() {} }
}
mod bar {
    // Разрешает `foo` из корня крейта.
    use foo::example::iter;
    // Префикс `::` явно разрешает `foo`
    // из корня крейта.
    use ::foo::baz::foobaz;
}

fn main() {}

Редакция 2015 не позволяет объявлениям use ссылаться на внешнюю прелюдию. Таким образом, объявления extern crate всё ещё требуются в 2015 для ссылки на внешний крейт в объявлении use. Начиная с редакции 2018, объявления use могут указывать внешнюю зависимость крейта так же, как extern crate.

Переименования с as

Ключевое слово as может использоваться для изменения имени импортированной сущности. Например:

#![allow(unused)]
fn main() {
// Создаёт непубличный псевдоним `bar` для функции `foo`.
use inner::foo as bar;

mod inner {
    pub fn foo() {}
}
}

Синтаксис фигурных скобок

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

#![allow(unused)]
fn main() {
// Создаёт привязки для:
// - `std::collections::BTreeSet`
// - `std::collections::hash_map`
// - `std::collections::hash_map::HashMap`
use std::collections::{BTreeSet, hash_map::{self, HashMap}};
}

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

2018 Edition differences

В редакции 2015 пути относительны к корню крейта, поэтому импорт типа use {foo, bar}; импортирует имена foo и bar из корня крейта, тогда как начиная с 2018 эти имена относительны к текущей области видимости.

Импорты self

Ключевое слово self может использоваться внутри синтаксиса фигурных скобок для создания привязки родительской сущности под её собственным именем.

mod stuff {
    pub fn foo() {}
    pub fn bar() {}
}
mod example {
    // Создаёт привязку для `stuff` и `foo`.
    use crate::stuff::{self, foo};
    pub fn baz() {
        foo();
        stuff::bar();
    }
}
fn main() {}

self создаёт привязку только из пространства имён типов родительской сущности. Например, в следующем импортируется только модуль foo:

mod bar {
    pub mod foo {}
    pub fn foo() {}
}

// Это импортирует только модуль `foo`. Функция `foo` находится в
// пространстве имён значений и не импортируется.
use bar::foo::{self};

fn main() {
    foo(); //~ ОШИБКА: `foo` является модулем
}

Note

self также может использоваться как первый сегмент пути. Использование self как первого сегмента и внутри фигурных скобок use логически одинаково; это означает текущий модуль родительского сегмента или текущий модуль, если нет родительского сегмента. См. self в главе о путях для получения дополнительной информации о значении ведущего self.

Глобальные импорты

Символ * может использоваться как последний сегмент пути use для импорта всех импортируемых сущностей из сущности предыдущего сегмента. Например:

#![allow(unused)]
fn main() {
// Создаёт непубличный псевдоним для `bar`.
use foo::*;

mod foo {
    fn i_am_private() {}
    enum Example {
        V1,
        V2,
    }
    pub fn bar() {
        // Создаёт локальные псевдонимы для `V1` и `V2`
        // перечисления `Example`.
        use Example::*;
        let x = V1;
    }
}
}

Элементы и именованные импорты могут затенять имена из глобальных импортов в том же пространстве имён. То есть, если имя уже определено другим элементом в том же пространстве имён, глобальный импорт будет затенён. Например:

#![allow(unused)]
fn main() {
// Это создаёт привязку к конструктору кортежной структуры `clashing::Foo`,
// но не импортирует её тип, потому что это бы
// конфликтовало со структурой `Foo`, определённой здесь.
//
// Заметьте, что порядок определения здесь неважен.
use clashing::*;
struct Foo {
    field: f32,
}

fn do_stuff() {
    // Использует конструктор из `clashing::Foo`.
    let f1 = Foo(123);
    // Выражение структуры использует тип из
    // структуры `Foo`, определённой выше.
    let f2 = Foo { field: 1.0 };
    // `Bar` также в области видимости из-за глобального импорта.
    let z = Bar {};
}

mod clashing {
    pub struct Foo(pub i32);
    pub struct Bar {}
}
}

* не может использоваться как первый или промежуточный сегмент.

* не может использоваться для импорта содержимого модуля в себя (например, use self::*;).

2018 Edition differences

В редакции 2015 пути относительны к корню крейта, поэтому импорт типа use *; допустим, и он означает импорт всего из корня крейта. Это не может использоваться в самом корне крейта.

Импорты с подчёркиванием

Элементы могут быть импортированы без привязки к имени с использованием подчёркивания в форме use path as _. Это особенно полезно для импорта трейта, чтобы его методы могли использоваться без импорта символа трейта, например, если символ трейта может конфликтовать с другим символом. Другой пример - это линковка внешнего крейта без импорта его имени.

Глобальные импорты звездочкой будут импортировать элементы, импортированные с _, в их неименуемой форме.

mod foo {
    pub trait Zoo {
        fn zoo(&self) {}
    }

    impl<T> Zoo for T {}
}

use self::foo::Zoo as _;
struct Zoo;  // Импорт с подчёркиванием избегает конфликта имён с этим элементом.

fn main() {
    let z = Zoo;
    z.zoo();
}

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

#![allow(unused)]
fn main() {
macro_rules! m {
    ($item: item) => { $item $item }
}

m!(use std as _;);
// Это раскрывается в:
// use std as _;
// use std as _;
}

Ограничения

Следующие ограничения действуют для допустимых объявлений use:

  • use crate; должен использовать as для определения имени, к которому привязать корень крейта.
  • use {self}; является ошибкой; должен быть ведущий сегмент при использовании self.
  • Как и с любым определением элемента, импорты use не могут создавать дублирующие привязки одного и того же имени в том же пространстве имён в модуле или блоке.
  • Пути use с $crate не разрешены в раскрытии macro_rules.
  • Пути use не могут ссылаться на варианты перечислений через псевдоним типа. Например:
    #![allow(unused)]
    fn main() {
    enum MyEnum {
        MyVariant
    }
    type TypeAlias = MyEnum;
    
    use MyEnum::MyVariant; //~ OK
    use TypeAlias::MyVariant; //~ ERROR
    }

Неоднозначности

Note

Этот раздел не завершён.

Некоторые ситуации являются ошибкой, когда есть неоднозначность в том, на какое имя ссылается объявление use. Это происходит, когда есть два кандидата на имя, которые не разрешаются в одну и ту же сущность.

Глобальные импорты разрешены для импорта конфликтующих имён в том же пространстве имён, пока имя не используется. Например:

mod foo {
    pub struct Qux;
}

mod bar {
    pub struct Qux;
}

use foo::*;
use bar::*; //~ OK, нет конфликта имён.

fn main() {
    // Это было бы ошибкой из-за неоднозначности.
    //let x = Qux;
}

Множественные глобальные импорты разрешены для импорта одного и того же имени, и это имя разрешено использовать, если импорты одного и того же элемента (следующие реэкспортам). Видимость имени - это максимальная видимость импортов. Например:

mod foo {
    pub struct Qux;
}

mod bar {
    pub use super::foo::Qux;
}

// Оба импортируют один и тот же `Qux`. Видимость `Qux`
// это `pub`, потому что это максимальная видимость между
// этими двумя объявлениями `use`.
pub use bar::*;
use foo::*;

fn main() {
    let _: Qux = Qux;
}