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;
}
}
No this is not possible. The compiler can't know which version you want, it deducts it from the parameters. You can overload many times, but not by the return type.
Only operators backed by traits can be overloaded. For example, the addition operator ( + ) can be overloaded through the Add trait, but since the assignment operator ( = ) has no backing trait, there is no way of overloading its semantics.
Can we overload all operators? Almost all operators can be overloaded except a few.
Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator between types, there's a specific trait that you can implement, which then overloads the operator.
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?
Operator Overloading - Rust By Example Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries. Introduction 1. Hello World 1.1. Comments 1.2. Formatted print 1.2.1. Debug 1.2.2. Display 1.2.2.1. Testcase: List 1.2.3. Formatting 2. Primitives 2.1. Literals and operators 2.2. Tuples
impl_trait_in_bindings — The key to our “true” function overloading, so far the most unstable feature, may cause the compiler to crash. I am using my functionate macro here but by the time you read this I might’ve added a feature to automatically create semi-overloaded-functions to it That’s a weird Rust piece of code.
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.
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)));
}
}
Playground
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With