Is it possible to overload a function with differe

2020-07-18 05:24发布

I'm trying to have a new constructor with one and with two arguments, but I can't seem to figure out how to do this. Is this even possible at the moment?

What I have now gives me an error that multiple applicable items are in scope (playground)

trait __Constructor1<T> {
    fn new(T) -> Self;
}
trait __Constructor2<T, U> {
    fn new(T, U) -> Self;
}

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl __Constructor1<i32> for MixedInts {
    fn new(__0: i32) -> MixedInts {
        MixedInts::SmallInt(__0)
    }
}
impl __Constructor2<i32, i32> for MixedInts {
    fn new(__0: i32, __1: i32) -> MixedInts {
        MixedInts::TwoSmallInts(__0, __1)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new(2i32, 2i32);
}

标签: rust
3条回答
Explosion°爆炸
2楼-- · 2020-07-18 06:05

It is technically possible, but not in a way that's practical. You need to use Rust's Universal Function Call Syntax in order for it to disambiguate the calls to new.

fn main() {
    let x = <MixedInts as __Constructor1<i32>>::new(2i32);
    let y = <MixedInts as __Constructor2<i32, i32>>::new(2i32, 2i32);
}

The Iron framework has an interesting Modifier pattern that I think accomplishes what you want. While it's pretty clever, it's ultimately confusing to the user.

查看更多
劫难
3楼-- · 2020-07-18 06:06

Rust doesn't support overloaded functions/methods. As a workaround, you can use tuples to receive multiple values in a single argument. You can then define a trait and implement it for the admissible types of that single argument, and the function will simply delegate to the trait's implementation.

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

trait IntoMixedInts {
    fn into(self) -> MixedInts;
}

impl MixedInts {
    fn new<A>(args: A) -> MixedInts
        where A: IntoMixedInts
    {
        args.into()
    }
}

impl IntoMixedInts for i32 {
    fn into(self) -> MixedInts {
        MixedInts::SmallInt(self)
    }
}

impl IntoMixedInts for (i32, i32) {
    fn into(self) -> MixedInts {
        MixedInts::TwoSmallInts(self.0, self.1)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new((2i32, 2i32));
}

Note: In this example, you could use the standard From and Into traits instead of defining your own trait. It might not work for other traits, though, due to the coherence rules (the rules that ensure that there can only exist one implementation of a certain trait for a certain type).

enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl MixedInts {
    fn new<A>(args: A) -> MixedInts
        where A: Into<MixedInts>
    {
        args.into()
    }
}

impl From<i32> for MixedInts {
    fn from(a: i32) -> MixedInts {
        MixedInts::SmallInt(a)
    }
}

impl From<(i32, i32)> for MixedInts {
    fn from((a, b): (i32, i32)) -> MixedInts {
        MixedInts::TwoSmallInts(a, b)
    }
}

fn main() {
    let x = MixedInts::new(2i32);
    let y = MixedInts::new((2i32, 2i32));
}
查看更多
Melony?
4楼-- · 2020-07-18 06:17

I would suggest making use of the From/Into traits in the standard library.

#[derive(PartialEq, Eq, Debug)]
enum MixedInts {
    SmallInt(i32),
    TwoSmallInts(i32, i32),
}

impl From<i32> for MixedInts {
    fn from(n: i32) -> Self {
        MixedInts::SmallInt(n)
    }
}

impl From<(i32, i32)> for MixedInts {
    fn from((a, b): (i32, i32)) -> Self {
        MixedInts::TwoSmallInts(a, b)
    }
}

fn main() {
    let x: MixedInts = 2_i32.into();
    assert_eq!(x, MixedInts::SmallInt(2));

    let y: MixedInts = (2_i32, 2_i32).into();
    assert_eq!(y, MixedInts::TwoSmallInts(2, 2));
}

example on Rust Playground

查看更多
登录 后发表回答