Как использовать перегрузку параметров или дополнительные параметры в rust?


Я пытаюсь написать функцию печати для бинарного дерева, и вот что у меня есть до сих пор:

impl TreeNode {
    fn print(&self) {
        self.print(0);
    }
    fn print(&self, level: u8) {
        for _i in range(0,level) {
            print!("t");
        }
        match self.data {
            Some(x) => println!("{}",x),
            None => ()
        };
        match self.left {
            Some(ref x) => x.print(level+1),
            None => ()
        };
        match self.right {
            Some(ref x) => x.print(level+1),
            None => ()
        };
    }
}

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

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

1 7

1 ответ:

Rust не имеет перегрузки, поэтому невозможно иметь две функции или методы с одинаковым именем и с разными наборами параметров.

Однако иногда можно эмулировать перегрузку с помощью признаков. Этот подход, вероятно, не подходит для вашего случая использования, но вы можете увидеть, как это делается в стандартной библиотеке , где Path::new() конструктор может быть вызван с чем-то, напоминающим вектор байтов:
Path::new("/a/b/c/d")   // argument is &str
Path::new(b"/a/b/c/d")  // argument is &[u8]
Path::new(Path::new("/a/b/c/d"))  // argument is another Path

Это делается через BytesContainer признак, и new() метод определяется следующим образом:

fn new<T: BytesContainer>(bytes: T) -> Path { ... }

Тогда эта черта реализуется для всех типов, которые вы хотите:

impl<'a> BytesContainer for &'a str { ... }
impl<'a> BytesContainer for &'a [u8] { ... }
impl BytesContainer for Path { ... }
// and more

Это напоминает перегрузку именно потому, что new() делает точно то же самое независимо от того, какой тип входных данных он предоставляет; это просто удобная вещь, которая делает Path конструктор более гибким. В конце концов new() просто преобразует свой аргумент в байтовый срез. Однако это не позволяет вам иметь совершенно разные функции с одним и тем же именем.