DEV Community

Fomalhaut Weisszwerg
Fomalhaut Weisszwerg

Posted on

4 1

How to overload method in Rust (amount of args differ).

Adapt version

$ rustc --version
rustc 1.55.0 (c8dfcfe04 2021-09-06)
Enter fullscreen mode Exit fullscreen mode

If you want to overload methods that have different amount of args likes following

// Constructor with 2 args.
fn new(arg0, arg1) -> Self {
    ...
}

// Constructor with 1 arg.
fn new(arg) -> Self {
    ...
}
Enter fullscreen mode Exit fullscreen mode

Macro is your better friend.

So macro can be used for pseud-overloading.

Pseud-overloading with macro.

struct SampleStruct {
    ip_address: IpAddr,
    port_number: u16,
    sample_socket: socket2::Socket,
}

macro_rules! SampleStruct_new {
    ($str_ip:expr , $num_port:expr) => ({
        let ip: IpAddr = $str_ip.parse::<IpAddr>()
            .unwrap_or_else( |_| { panic!("`address` MUST be an IPv4 address or IPv6 address.") });

        SampleStruct {
            ip_address: ip,
            port_number: $num_port,
            sample_socket: Socket::new(
                if ip.is_ipv4() { Domain::IPV4 } else { Domain::IPV6 },
                Type::DGRAM,
                Some(Protocol::UDP)
            ).unwrap()
        }
    });

    ($obj_SocketAddr:expr) => ({
        SampleStruct {
            ip_address: $obj_SocketAddr.ip(),
            port_number: $obj_SocketAddr.port(),
            sample_socket: Socket::new(
                if $obj_SocketAddr.ip().is_ipv4() { Domain::IPV4 } else { Domain::IPV6 },
                Type::DGRAM,
                Some(Protocol::UDP)
            ).unwrap()
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

Then it uses as following:

fn main() {
    let foo = SampleStruct_new!("127.0.0.1", 12345);
    println!("IP address = {}, Port = {}", foo.ip_address.to_string(), foo.port_number);

    let ipv6_sock_addr = SocketAddr::new("::1".parse::<IpAddr>().unwrap(), 12345);
    let bar = SampleStruct_new!(ipv6_sock_addr);
    println!("IP address = {}, Port = {}", bar.ip_address.to_string(), bar.port_number);
}
Enter fullscreen mode Exit fullscreen mode

To see a sample code, go Rust playground

Generics with placeholder.

Generics with placeholder is also your frind. _:() in impl block means "this is unused argument".

trait SampleTrait<T, O> {
    fn new(address:T, port:O) -> SampleStruct;
}

impl SampleTrait<&str, u16> for SampleStruct {
    fn new(address: &str, port: u16) -> Self {
        let addr = address.to_string().parse::<IpAddr>()
            .unwrap_or_else( |_| { panic!("`address` MUST be an IPv4 address (dotted-decimal form) or an IPv6 address.") });

        return SampleStruct {
            ip_address: addr,
            port_number: port,
            sample_socket: Socket::new(
                if addr.is_ipv4() { Domain::IPV4 } else { Domain::IPV6 },
                Type::DGRAM,
                Some(Protocol::UDP)
            ).unwrap()
        }
    }
}

impl SampleTrait<SocketAddr, ()> for SampleStruct {
    fn new(address: SocketAddr, _:()) -> Self {
        return SampleStruct {
            ip_address: address.ip(),
            port_number: address.port(),
            sample_socket: Socket::new(
                if address.ip().is_ipv4() { Domain::IPV4 } else { Domain:: IPV6 },
                Type::DGRAM,
                Some(Protocol::UDP)
            ).unwrap()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

When calling fn new(address: SocketAddr, _:()), the () MUST be passed to unused args. So it seems slightly ugly in this way.

fn main() {
    let foo = SampleStruct::new("127.0.0.1".to_string(), 12345);
    println!("IP address = {}, Port = {}", foo.ip_address.to_string(), foo.port_number);

    let ipv6_sock_addr = SocketAddr::new("::1".parse::<IpAddr>().unwrap(), 12345);
    let baz = SampleStruct::new(ipv6_sock_addr, ());
    println!("IP address = {}, Port = {}", baz.ip_address.to_string(), baz.port_number);
}
Enter fullscreen mode Exit fullscreen mode

To see a sample code, go Rust playground

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (1)

Collapse
 
aboss123 profile image
Ashish Bailkeri

Nice trick!

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay