How do I use parameter overloading or optional par

2019-06-18 05:02发布

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.

1条回答
▲ chillily
2楼-- · 2019-06-18 05:30

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.

查看更多
登录 后发表回答