Problem: Let say I wanna pass a value into a function increment it and return the result:
fn add_one <T> (x: &T) {
x += 1 as T;
}
fn add_one_x <T> (x: T)-> T {
x += 1 as T
}
fn main(){
let mut x = 5i32;
// I expect the x will be 6 after add_one
add_one::<i32>(&x);
// I expect the y will be 7 after add_one_x
let y = add_one_x::<i32>(x);
println!("{}", y)
}
use std::ops::{Add, AddAssign};
use num::One;
fn add_one <T: AddAssign + One> (x: &mut T) {
*x += T::one();
}
fn add_one_x <T: Add<Output = T> + One> (x: T) -> T {
x + T::one()
}
fn main() {
let mut x = 5i32;
// I expect the x will be 6 after add_one
add_one(&mut x);
// I expect the y will be 7 after add_one_x
let y = add_one_x(x);
println!("{}", y)
}
You will also need to add the num crate to you Cargo.toml
ok this works but it seams a bit excessive ... might I ask for a bit of explanation. My intention was to pass a value regardless whether it is i32, i64, i16, etc. and increment it , but what if i wanted to multiply, divide of pass a float or increment by 4 ... Is there a more generic way to do this ? (or am i asking stupid questions )
If you define a function as fn foo<T>(x: T), you're effectively saying 'this function can take literally any type'. But looking at the implemention, that's not true - your function will only work with types that can be added, and that can represent the number one in some form. So you need to make those constraints known to the compiler - this is possible to do without external crates, but would require a lot of boilerplate that num implements for you.
Here's a translation of the type constraints to plain English:
T: AddAssign + One: T must be a type that:
Implements the trait AddAssign (which is used to implement Rust's += operator).
Implements the trait One (which is implemented by the num crate for all numeric types that can represent the number one).
T: Add<Output = T> + One: T must be a type that:
Implements the trait Add (which is used to implement Rust's + operator) in such a manner that the output of the addition is also of type T.
This won't work for floats, and other numeric types defined in other crates, so I wouldn't use it. Better to use From<u8> if you don't want the dependency. This will cover all numeric types in std except i8
You mean to use it only with numeric types, but Rust doesn't know that. When you write a generic type T without constraints, Rust literally allows it to be any type. It allows it to be a String, a reference, an array of 17 File handles, an image of a cat. And + and as casts aren't guaranteed to work for all of these, so your function is rejected.