Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use parameter overloading or optional parameters in rust?

I am trying to write a print function for a binary tree and here is what I have so far:

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 => ()
        };
    }
}

I am getting the error: duplicate definition of value print. So I was wondering if there is a way to create functions with the same name but different arguments. Alternatively optional parameters would solve this problem, but I don't think that is possible at the moment (at least I couldn't find it via a Google search).

So, what is the best way to do this? Renaming the second print function works but looks ugly and requires you to remember more than one function name if I want to (for this example) print starting from the middle of the tree.

like image 469
user439299 Avatar asked Jul 24 '14 14:07

user439299


People also ask

Does rust have optional parameters?

If you come to Rust from languages like Javascript which have support for optional arguments in functions, you might find it inconvenient that there is no way to omit arguments in Rust.

How do you overload a function in Rust?

Rust does not support traditional overloading where the same method is defined with multiple signatures. But traits provide much of the benefit of overloading: if a method is defined generically over a trait, it can be called with any type implementing that trait.


1 Answers

Rust does not have overloading, so it is impossible to have two functions or methods with the same name and with different sets of parameters.

However, it is sometimes possible to emulate overload with traits. This approach is likely inappropriate for your use case, but you can see how it is done in the standard library, where Path::new() constructor can be called with something resembling a vector of bytes:

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

This is done via BytesContainer trait, and new() method is defined like this:

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

Then this trait is implemented for all the types you want:

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

This resembles overloading precisely because new() does exactly the same thing regardless of what kind of input it is provided; it is just a convenience thing which makes Path constructor more flexible. In the end new() just converts its argument to a byte slice. However, this does not allow you to have completely different functions with the same name.

like image 128
Vladimir Matveev Avatar answered Oct 10 '22 20:10

Vladimir Matveev