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