How can I approximate method overloading?

2019-01-15 18:51发布

I am modeling an API where method overloading would be a good fit. My naïve attempt failed:

// fn attempt_1(x: int) {}
// fn attempt_1(x: f32) {}
// Error: duplicate definition of value `attempt_1`

I then added an enum and worked through to:

enum IntOrFloat {
  Int(int),
  Float(f32),
}

fn attempt_2(x: IntOrFloat) {}

fn main() {
  let i: int = 1;
  let f: f32 = 3.0;

  // Can't pass the value directly
  // attempt_2(i);
  // attempt_2(f);
  // Error: mismatched types: expected `IntOrFloat`

  attempt_2(Int(i));
  attempt_2(Float(f));
  // Ugly that the caller has to explicitly wrap the parameter 
}

Doing some quick searches, I've found some references that talk about overloading, and all of them seem to end in "we aren't going to allow this, but give traits a try". So I tried:

enum IntOrFloat {
  Int(int),
  Float(f32),
}

trait IntOrFloatTrait {
  fn to_int_or_float(&self) -> IntOrFloat;
}

impl IntOrFloatTrait for int {
  fn to_int_or_float(&self) -> IntOrFloat { Int(*self) }
}

impl IntOrFloatTrait for f32 {
  fn to_int_or_float(&self) -> IntOrFloat { Float(*self) }
}

fn attempt_3(x: &IntOrFloatTrait) {}

fn main() {
  let i: int = 1;
  let f: f32 = 3.0;

  attempt_3(&i);
  attempt_3(&f);
  // Better, but the caller still has to explicitly take the reference
}

Is this the closest I can get to method overloading? Is there a cleaner way?

1条回答
手持菜刀,她持情操
2楼-- · 2019-01-15 19:18

Yes, there is, and you almost got it already. Traits are the way to go, but you don't need trait objects, use generics:

#[derive(Debug)]
enum IntOrFloat {
    Int(i32),
    Float(f32),
}

trait IntOrFloatTrait {
    fn to_int_or_float(&self) -> IntOrFloat;
}

impl IntOrFloatTrait for i32 {
    fn to_int_or_float(&self) -> IntOrFloat {
        IntOrFloat::Int(*self)
    }
}

impl IntOrFloatTrait for f32 {
    fn to_int_or_float(&self) -> IntOrFloat {
        IntOrFloat::Float(*self)
    }
}

fn attempt_4<T: IntOrFloatTrait>(x: T) {
    let v = x.to_int_or_float();
    println!("{:?}", v);
}

fn main() {
    let i: i32 = 1;
    let f: f32 = 3.0;

    attempt_4(i);
    attempt_4(f);
}

See it working here.

查看更多
登录 后发表回答