Can I define my own operator symbol in Rust? [duplicate] - rust

This question already has an answer here:
Can we create custom Rust operators?
(1 answer)
Closed 1 year ago.
Can I define my own operator symbol in Rust? If so, how?
For example, a + b is equivalent to a.add(b). Can I define a symbol like ~ so that a ~ b is equivalent to a.myop(b) for some method myop? (I'm assuming ~ has no other meaning in Rust which I think is true.)
Of course I would expect this operator to be implemented the same way operators in std::ops are, so an implementation would look like:
impl<T> MyOp<T> for MyStruct {
type Output = x;
fn myop(self, other: T) -> x {
...
}
}
Also, if this is possible what symbols are allowed?

No.
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. Additionally, this module does not provide any mechanism to create new operators.
https://doc.rust-lang.org/std/ops/index.html

Related

what does the '->' token mean in Rust? [duplicate]

This question already has an answer here:
What's the origin of -> in Rust function definition return types?
(1 answer)
Closed last month.
I'm digging into Rust for the first time, with a primarily ObjC and Javascript (sigh) background, and working with a few of the playgrounds.
I'm trying to understand the -> (aka "thin arrow??") symbol in Rust and how I am supposed to interpret this when reading Rust statements
In Rust -> specifies the return type of the function. In Rust, functions need to specify their return type (if it isn't (), the empty return type).
So when you declare a function that adds one to an i32, you have to specify the return type i32 of the function like this:
fn add_one(x: i32) -> i32
{
x+1
}
You have to declare x+1 to add one and return the value. Note that when you return the value you do not use a semicolon after x+1;. A semicolon means it is a statement and not a return expression. In Rust, expressions without semicolons are return value expressions.

How to I implement a trait on a builtin in Rust? [duplicate]

This question already has answers here:
How do I implement a trait I don't own for a type I don't own?
(3 answers)
Closed 2 months ago.
In Rust :
let int: i32 = 3;
let float: f32 = 3.3;
let res = int*float; // Invalid
let res = (int as f32)*float; // Valid
To make this easier, I'm looking to implement an override on the * operator, which seems to be possible given Rust's error message :
cannot multiply `{integer}` by `{float}`
the trait `Mul<{float}>` is not implemented for `{integer}`
the following other types implement trait `Mul<Rhs>`:
But writing impl Mul<i32> for f32 is apparently not possible either :
only traits defined in the current crate can be implemented for primitive types
define and implement a trait or new type instead
So how is that supposed to be done ? Is there a crate already implementing those ?
You can't implement Mul for a primitive. This is part of rusts foreign type rules: For an implementation in your crate, at least one of the implemented type or trait must have been defined in your crate. Since neither Mul nor the primitive are defined in your code, you can't create an implementation for them.
If you really want to do this, you need to create a wrapper type around f32, and implement Mul and all the other relevant operators on that.

How can I implement traits for type aliases? [duplicate]

This question already has an answer here:
Is it possible to implement methods on type aliases?
(1 answer)
Closed 3 years ago.
I have some code like this:
type MyFn = Box<Fn(usize) -> bool>;
fn main() {
let my_fn: MyFn = Box::new(|x: usize| x > 10);
dbg!(my_fn);
}
This doesn't compile because MyFn doesn't implement std::fmt::Debug. That's reasonable, so what if I try to implement it for MyFn?
It fails saying:
conflicting implementations of trait std::fmt::Debug for type std::boxed::Box<(dyn std::ops::Fn(usize) -> bool + 'static)>
As well as:
only traits defined in the current crate can be implemented for arbitrary types
How can I implement Debug and other traits for MyFn?
Creating a type alias does not create an entirely new type, it just allows you to refer to the existing type via a different name. Therefore, trying to implement Debug for MyFn is exactly the same as trying to implement it for Box<Fn(usize) -> bool> - which is not allowed, since your crate doesn't own the type or the trait. Rust's 'orphan rules' require your crate to have defined one or both for the implementation to be valid.
A common pattern to get around this is to create a 'newtype' struct, which wraps the type:
struct MyFn(Box<Fn(usize) -> bool>);
You can implement Debug for this struct, as the struct comes from your crate.

About trait Index implement of Vector in Rust [duplicate]

This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
Closed 4 years ago.
I check Index trait in doc and find return type of index() is &T.
Then I write this function to get value from vector:
fn get_value_test(a: usize, v: &Vec<i32>) -> i32 {
v[a]
}
My question is: why v[a] is i32 but &i32? Because i32 ...have a known size at compile time are stored entirely on the stack, so copies of the actual values are quick to make? (from here)
It looks like Rust have hidden rule to convert type in this situation?
There was a small misguidance here. Although the method prototype for Index<Idx> is fn index(&self, index: Idx) -> &T, the syntactical operator x[i] does dereference the output from that &T:
container[index] is actually syntactic sugar for *container.index(index) [...]. This allows nice things such as let value = v[index] if the type of value implements Copy.
So there you go. Your function is indeed returning a copy of the value from the vector, but not from an implicit conversion. If the original intent was to really retrieve a reference to that value, you would do &x[i].
See also:
Meaning of the ampersand '&' and star '*' symbols in Rust
Does Rust automatically dereference primitive type references?

Does Rust support using an infix operator as a function?

I am writing a function that does piecewise multiplication of two arrays.
xs.iter()
.zip(ys).map(|(x, y)| x * y)
.sum()
In some other languages, I can pass (*) as a function to map. Does Rust have this feature?
Nnnyes. Sorta kinda not really.
You can't write an operator as a name. But most operators are backed by traits, and you can write the name of those, so a * b is effectively Mul::mul(a, b), and you can pass Mul::mul as a function pointer.
But that doesn't help in this case because Iterator::map is expecting a FnMut((A, B)) -> C, and the binary operators all implement FnMut(A, B) -> C.
Now, you could write an adapter for this, but you'd need one for every combination of arity and mutability. And you'd have to eat a heap allocation and indirection or require a nightly compiler.
Or, you could write your own version of Iterator::map on an extension trait that accepts higher arity functions for iterators of tuples... again, one for each arity...
Honestly, it's simpler to just use a closure.
Rust does not have any syntax to pass infix operators, mostly because it is redundant anyway.
In Rust, each operator maps to a trait: * maps to the std::ops::Mul trait, for example.
Therefore, using * directly should be using std::ops::Mul::mul:
xs.iter().zip(ys).map(Mul::mul).sum();
However there are several difficulties:
Generally, iterators yield references while Mul is implemented for plain values,
Mul::mul expects two arguments, xs.zip(ys) yields a single element (a tuple of two elements).
So, you need to go from reference to value and then "unpack" the tuple and... it ends up being shorter to use a closure.
No. The * operator is implemented in std::Ops::Mul, but it can't be used directly:
use std::ops::Mul::mul;
fn main() {
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
println!("{:?}", v1.iter().zip(v2).map(|(x, y)| mul).collect());
}
Will result in the following error:
error[E0253]: `mul` is not directly importable
--> <anon>:1:5
|
1 | use std::ops::Mul::mul;
| ^^^^^^^^^^^^^^^^^^ cannot be imported directly
You could introduce your own function using the * operator, but there wouldn't be much added value :).

Resources