Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
662 views
in Technique[技术] by (71.8m points)

rust - How can I approximate method overloading?

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

// fn attempt_1(_x: i32) {}
// fn attempt_1(_x: f32) {}
// Error: duplicate definition of value `attempt_1`

I then added an enum and worked through to:

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

fn attempt_2(_x: IntOrFloat) {}

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

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

    attempt_2(IntOrFloat::Int(i));
    attempt_2(IntOrFloat::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(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_3(_x: &dyn IntOrFloatTrait) {}

fn main() {
    let i: i32 = 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...