Numbers and casts
Integers of any width, floats, how values widen, and casts with as.
Number types
ianduwith a width give signed and unsigned integers of any width from 1 bit up to 2^23 bits:i8,u24,i200, and so on.usizeis as wide as a pointer on the target machine.f32andf64are floats.
A literal takes the type it is used as, or the one its suffix names. _ can
separate digits.
const Bits: u8 = 1u8 << 7; // 128
const Big: i128 = 1i128 << 100;
const Odd: u24 = 0xFF_FFFF; // hex, with `_` between digitsWidening
A value widens on its own when the new type can hold every value of the old
one, so a u8 goes into an i16 or a u32 without a cast. Any other change
needs as. The result of an operator has the type of its left operand.
let small: u8 = 200;
let signed: i16 = small;
let unsigned: u32 = small;// Numbers: signed `i` and unsigned `u` integers of any width from 1 to 2^23
// bits (`i8`, `u24`, `i200`, ...), `usize` as wide as a pointer, and `f32`
// and `f64` floats. A literal takes the type it is used as, or the one its
// suffix names; constants fold while compiling.
// Run: peeper run examples/02_numbers.peep
const Bits: u8 = 1u8 << 7; // 128
const Big: i128 = 1i128 << 100;
const Odd: u24 = 0xFF_FFFF; // hex, with `_` between digits
const Half: f32 = 0.5f32;
fn main() {
println("constants:", Bits, Big, Odd, Half);
// A value widens on its own when the new type holds every value of the
// old one; anything else needs `as` (examples/03_casts.peep).
let small: u8 = 200;
let signed: i16 = small;
let unsigned: u32 = small;
let float: f64 = Half;
println("widened:", signed, unsigned, float);
// The result of an operator has the left operand's type.
let x: i32 = 17;
println("arithmetic:", x + 3, x - 20, x * 2, x / 5, x % 5, -x);
println("bitwise:", x & 0xF, x | 0x100, x ^ 1, ~x, x << 2, x >> 1);
println("compare:", x == 17, x != 17, x < 20, x >= 18);
let wide: i200 = -1;
let top: u128 = 340282366920938463463374607431768211455;
let size: usize = 4096;
println("wide:", wide, top, size);
let third = 1.0 / 3.0; // `f64` unless used as an `f32`
println("floats:", third, 0.1 + 0.2, 1e16, 2.5e-3);
}constants: 128 1267650600228229401496703205376 16777215 0.5
widened: 200 200 0.5
arithmetic: 20 -3 34 3 2 -17
bitwise: 1 273 16 -18 68 8
compare: true false true false
wide: -1 340282366920938463463374607431768211455 4096
floats: 0.3333333333333333 0.30000000000000004 1e+16 0.0025Casts
value as T turns any number or bool into any number type:
- An integer cast keeps the low bits.
- A float cast to an integer drops the fraction and stops at the type's smallest or largest value. NaN gives 0.
A narrowing without as is an error, and the error offers the cast as a fix:
[T0001]: mismatched types: expected `u8`, found `i32` --> src/main.peep:3:21 | 2 | let big: i32 = 300;3 | let small: u8 = big; | ^^^ | = help: add `as u8` to convert, which can change the value | 3 | let small: u8 = big as u8;Compilation failed with 1 error(s)// Casts: `value as T` turns any number or `bool` into any number type. An
// integer cast keeps the low bits; a float cast to an integer drops the
// fraction and saturates at the type's ends, and NaN gives 0.
// Run: peeper run examples/03_casts.peep
fn main() {
let big: i32 = 300;
let negative: i32 = -1;
println("integers:", big as u8, negative as u32, negative as i64);
let half: f64 = -2.5;
let huge: f64 = 1e20;
let zero = 0.0;
println("floats to integers:", half as i32, half as u16, huge as i32, (zero / zero) as i32);
let count: i64 = 7;
println("integers to floats:", count as f64 / 2.0, 0.1 as f32);
println("bools:", true as u8, false as i32);
}integers: 44 4294967295 -1
floats to integers: -2 0 2147483647 0
integers to floats: 3.5 0.1
bools: 1 0