Reputation: 5523
I know it is possible by using traits to implement operator overloading in Rust. In C++ is also possible to have multiple operator overloading for the same operator and the same struct
, and switch on/off which operator to use.
Is it possible to do the same as the following C++ code in Rust? Possibly in the same source file?
struct S
{
int value;
};
namespace first
{
S operator+(S lhs, S rhs)
{
return S{ lhs.value + rhs.value };
}
}
namespace second
{
S operator+(S lhs, S rhs)
{
return S{ lhs.value * rhs.value };
}
}
int main()
{
S s1{5};
S s2{10};
{
using namespace first;
S s3 = s1 + s2;
std::cout << s3.value << std::endl;
}
{
using namespace second;
S s3 = s1 + s2;
std::cout << s3.value << std::endl;
}
}
Upvotes: 7
Views: 1822
Reputation: 299790
The idiomatic answer in Rust to:
How do I use different overloads of +, <, ... for my Type?
is to wrap the type up and implement the operator on the wrapper.
Example on the playground
#[derive(Clone, Copy, Debug)]
struct S(i32);
#[derive(Debug)]
struct Adder(pub S);
impl std::ops::Add<S> for Adder {
type Output = S;
fn add(self, other: S) -> S { S(self.0.0 + other.0) }
}
impl std::ops::Add<Adder> for S {
type Output = S;
fn add(self, other: Adder) -> S { S(self.0 + other.0.0) }
}
#[derive(Debug)]
struct Multiplier(pub S);
impl std::ops::Add<S> for Multiplier {
type Output = S;
fn add(self, other: S) -> S { S(self.0.0 * other.0) }
}
impl std::ops::Add<Multiplier> for S {
type Output = S;
fn add(self, other: Multiplier) -> S { S(self.0 * other.0.0) }
}
fn main() {
let one = S(5);
let two = S(10);
println!("{:?}", one + Adder(two));
println!("{:?}", Adder(one) + two);
println!("{:?}", one + Multiplier(two));
println!("{:?}", Multiplier(one) + two);
}
This idiom can be seen in the standard library where the std::num::Wrapping
type can be used to wrap an integer in which case addition, subtraction, and multiplication are re-defined to use modulo arithmetic.
Upvotes: 7
Reputation: 42678
Is it possible to do the same as the following C++ code in Rust? Possibly in the same source file?
No, it is not (not exactly) for the following reasons:
Regarding what you want in your code, you can approximate it like this:
#[derive(Debug)]
struct S(i32);
mod first {
use crate::S;
pub trait Foo {
fn bar(self, s: S) -> S;
}
impl Foo for S {
fn bar(self, s: S) -> S {
S(self.0 + s.0)
}
}
}
mod second {
use crate::S;
pub trait Foo {
fn bar(self, s: S) -> S;
}
impl Foo for S {
fn bar(self, s: S) -> S {
S(self.0 * s.0)
}
}
}
fn main() {
let first_res = first::Foo::bar(S(1), S(2));
let second_res = second::Foo::bar(S(1), S(2));
println!("{:?}, {:?}", first_res, second_res);
{
use first::Foo;
println!("{:?}", S(1).bar(S(2)));
}
{
use second::Foo;
println!("{:?}", S(1).bar(S(2)));
}
}
Notice that the Foo
traits are indeed different traits for the compiler. So you are implementing two different traits, not one. For the same reason, both bar
methods are different ones too.
Upvotes: 4