Конфликты разрешения методов
Что происходит, когда возникает конфликт имён между собственным методом и методом-расширением?
// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0
mod ext {
pub trait CountOnesExt {
fn count_ones(&self) -> u32;
}
impl CountOnesExt for i32 {
fn count_ones(&self) -> u32 {
let value = *self;
(0..32).filter(|i| ((value >> i) & 1i32) == 1).count() as u32
}
}
}
fn main() {
pub use ext::CountOnesExt;
// Какой метод `count_ones` будет вызван?
// Тот, что из `CountOnesExt`? Или собственный метод `i32`?
assert_eq!((-1i32).count_ones(), 32);
}
-
Внешний тип в новой версии может добавить новый собственный метод с тем же именем, что и наш метод-расширение.
Спросите: что произойдёт в примере выше? Будет ли ошибка компиляции? Получит ли один из двух методов более высокий приоритет? Какой именно?
Добавьте
panic!("Extension trait");в телоCountOnesExt::count_ones, чтобы понять, какой метод вызывается. -
Когда собственный метод и метод трейта имеют одно и то же имя и тип получателя, правила разрешения методов в Rust автоматически выберут один из них. Как правило, предпочтение отдаётся собственному методу, но правила разрешения методов могут быть тонкими и неожиданными.
Продемонстрируйте: измените вызов на
(&-1i32).count_ones()и покажите, что теперь вызывается метод трейта. Затем измените метод трейта так, чтобы он принималself(вместо&self), и покажите, что снова вызывается собственный метод. -
Избегайте конфликтов имён между методами трейтов-расширений и собственными методами. Алгоритм разрешения методов в Rust сложен и может удивить пользователей вашего кода.
Для дальнейшего изучения
- Взаимодействие приоритетного поиска, который использует алгоритм разрешения методов Rust, и автоматического
Derefможно применить для эмуляции специализации на стабильном тулчейне, в первую очередь в контексте кода, сгенерированного макросами. Подробности см. в статье «Autoref Specialization».