How do I use integer number literals when using generic types?
Many things are going wrong here:
-
As Shepmaster says,
0
and1
cannot be converted to everything implementingInteger
. UseZero::zero
andOne::one
instead. -
10
can definitely not be converted to anything implementingInteger
, you need to useNumCast
for that -
a /= b
is not sugar fora = a / b
but an separate trait thatInteger
does not require. -
-x
is an unary operation which is not part ofInteger
but requires theNeg
trait (since it only makes sense for signed types).
Here's an implementation. Note that you need a bound on Neg
, to make sure that it results in the same type as T
extern crate num;
use num::{Integer, NumCast};
use std::ops::Neg;
fn int_length<T>(mut x: T) -> u8
where
T: Integer + Neg<Output = T> + NumCast,
{
if x == T::zero() {
return 1;
}
let mut length = 0;
if x < T::zero() {
length += 1;
x = -x;
}
while x > T::zero() {
x = x / NumCast::from(10).unwrap();
length += 1;
}
length
}
fn main() {
println!("{}", int_length(45));
println!("{}", int_length(-45));
}
The problem is that the Integer
trait can be implemented by anything. For example, you could choose to implement it on your own struct! There wouldn't be a way to convert the literal 0
or 1
to your struct. I'm too lazy to show an example of implementing it, because there's 10 or so methods. ^_^
num::Zero
and num::One
This is why Zero::zero
and One::one
exist. You can (very annoyingly) create all the other constants from repeated calls to those.
use num::{One, Zero}; // 0.4.0
fn three<T>() -> T
where
T: Zero + One,
{
let mut three = Zero::zero();
for _ in 0..3 {
three = three + One::one();
}
three
}
From
and Into
You can also use the From
and Into
traits to convert to your generic type:
use num::Integer; // 0.4.0
use std::ops::{DivAssign, Neg};
fn int_length<T>(mut x: T) -> u8
where
T: Integer + Neg<Output = T> + DivAssign,
u8: Into<T>,
{
let zero = 0.into();
if x == zero {
return 1;
}
let mut length = 0u8;
if x < zero {
length += 1;
x = -x;
}
while x > zero {
x /= 10.into();
length += 1;
}
length
}
fn main() {
println!("{}", int_length(45));
println!("{}", int_length(-45));
}
See also:
- How do I use floating point number literals when using generic types?