For learning purposes, I tried this solution, but it does not work:
use std::ops::Add;
fn inc<T: Add>(x:&mut T) {
*x += 1;
}
fn main() {
let mut x:i32 = 10;
let mut y:u8 = 1;
inc(&mut x);
inc(&mut y);
println!("{} {}", x, y);
}
Error message:
<anon>:4:5: 4:7 error: binary assignment operation `+=` cannot be applied to types `T` and `_` [E0368]
<anon>:4 *x += 1;
^~
<anon>:4:5: 4:7 help: see the detailed explanation for E0368
error: aborting due to previous error
What is the right way to do that?
The most simple way to increment/decrement a variable is by using the + and - operators. This method allows you increment/decrement the variable by any value you want.
4.16. A program can increment by 1 the value of a variable called c using the increment operator, ++, rather than the expression c=c+1 or c+=1. An increment or decrement operator that is prefixed to (placed before) a variable is referred to as the prefix increment or prefix decrement operator, respectively.
In C/C++, Increment operators are used to increase the value of a variable by 1. This operator is represented by the ++ symbol. The increment operator can either increase the value of the variable by 1 before assigning it to the variable or can increase the value of the variable by 1 after assigning the variable.
At present, +=
is only defined on the primitive integer types; generically, you will need to expand it to *x = *x + 1;
instead. This then reveals more problems:
<anon>:4:15: 4:16 error: mismatched types:
expected `T`,
found `_`
(expected type parameter,
found integral variable) [E0308]
<anon>:4 *x = *x + 1;
^
<anon>:4:10: 4:16 error: mismatched types:
expected `T`,
found `<T as core::ops::Add>::Output`
(expected type parameter,
found associated type) [E0308]
<anon>:4 *x = *x + 1;
^~~~~~
error: aborting due to 2 previous errors
Let’s look at the Add
trait’s definition:
pub trait Add<RHS = Self> {
/// The resulting type after applying the `+` operator
type Output;
/// The method for the `+` operator
fn add(self, rhs: RHS) -> Self::Output;
}
So Self + RHS
produces an object of type <Self as Add<RHS>>::Output
.
As you’re storing the value back in *x
, the result of the calculation must be a T
; thus we establish that the bound on T
will need to be not Add
but Add<???, Output = T>
.
What, then, will ???
be? What is the type of 1
? It’s not generic; it’s one of the ten known primitive integer types (isize
, i8
, i16
, i32
, i64
, usize
, u8
, u16
, u32
, u64
). This clearly won’t work, because the integral types don’t implement addition of lesser types—the default value for RHS
of Self
(that is, where T: Add
means T: Add<Self>
) is all you can count on, but 1
cannot be of type T
.
The solution is to use a generic function that produces the value 1. There is one unstable in std::num::One
, and a stable one in the num
crate from crates.io, num::One
. Using the former requires the Rust nightly, using the latter requires dropping the std::
, adding an extern crate num;
and adding num
to your Cargo.toml dependencies section.
We also need a Copy
bound to allow the *x
of *x + 1
to work.
Here’s the final result:
#![feature(zero_one)]
use std::ops::Add;
use std::num::One;
fn inc<T: Copy + One + Add<T, Output = T>>(x: &mut T) {
*x = *x + T::one();
}
fn main() {
let mut x: i32 = 10;
let mut y: u8 = 1;
inc(&mut x);
inc(&mut y);
println!("{} {}", x, y);
}
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