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

Выражения вызовов методов

Syntax
MethodCallExpressionExpression . PathExprSegment ( CallParams? )

Вызов метода состоит из выражения (называемого получателем), за которым следует точка, сегмент пути выражения и заключенный в круглые скобки список выражений.

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

#![allow(unused)]
fn main() {
let pi: Result<f32, _> = "3.14".parse();
let log_pi = pi.unwrap_or(1.0).log(2.72);
assert!(1.14 < log_pi && log_pi < 1.15)
}

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

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

Затем для каждого кандидата T добавьте &T и &mut T в список сразу после T.

Например, если получатель имеет тип Box<[i32;2]>, то кандидатами будут типы Box<[i32;2]>, &Box<[i32;2]>, &mut Box<[i32;2]>, [i32; 2] (путем разыменования), &[i32; 2], &mut [i32; 2], [i32] (путем неразмерного приведения), &[i32] и, наконец, &mut [i32].

Затем для каждого кандидата типа T выполните поиск видимого метода с получателем этого типа в следующих местах:

  1. Собственные методы T (методы, реализованные непосредственно на T).
  2. Любые методы, предоставляемые видимым трейтом, реализованным для T. Если T является параметром типа, сначала ищутся методы, предоставляемые ограничениями трейтов на T. Затем ищутся все оставшиеся методы в области видимости.

Note

Поиск выполняется для каждого типа по порядку, что иногда может приводить к неожиданным результатам. Следующий код напечатает “In trait impl!”, потому что методы &self ищутся первыми, и метод трейта находится до того, как будет найден метод &mut self структуры.

struct Foo {}

trait Bar {
  fn bar(&self);
}

impl Foo {
  fn bar(&mut self) {
    println!("In struct impl!")
  }
}

impl Bar for Foo {
  fn bar(&self) {
    println!("In trait impl!")
  }
}

fn main() {
  let mut f = Foo{};
  f.bar();
}

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

Этот процесс не учитывает изменяемость или время жизни получателя, а также то, является ли метод unsafe. После того как метод найден, если он не может быть вызван по одной (или нескольким) из этих причин, результатом является ошибка компилятора.

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

2021 Edition differences

До редакции 2021 года, во время поиска видимых методов, если кандидат-тип получателя является типом массива, методы, предоставляемые стандартной библиотекой трейтом IntoIterator, игнорировались.

Редакция, используемая для этой цели, определяется токеном, представляющим имя метода.

Этот особый случай может быть удален в будущем.

Warning

Для трейт-объектов, если существует собственный метод с тем же именем, что и метод трейта, это вызовет ошибку компилятора при попытке вызвать метод в выражении вызова метода. Вместо этого вы можете вызвать метод, используя синтаксис разрешения неоднозначности вызовов функций, в этом случае будет вызван метод трейта, а не собственный метод. Нет способа вызвать собственный метод. Просто не определяйте собственные методы на трейт-объектах с тем же именем, что и метод трейта, и все будет хорошо.