Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement variable increment via side effect?

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?

like image 648
hxwalker Avatar asked Jun 21 '15 22:06

hxwalker


People also ask

How do you increment variables?

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.

How can we increment the value of a variable named as a by one?

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.

How do you increment a variable in C++?

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.


1 Answers

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);
}
like image 115
Chris Morgan Avatar answered Nov 15 '22 08:11

Chris Morgan