Casts
Rux converts a value to another type only when asked. The as operator is the request:
cast = operand "as" type
let ratio = count as float64 / total as float64;
The right side is a type, not an expression. It is a postfix type — a name with any ?, [], [N] or [..] suffixes — so a sum or fallible target must be grouped: value as (T ! E). Writing f as int32 ! bool is error: a fallible type after 'as' must be grouped.
as is on level 15, above every binary operator and below the prefix ones. It converts only the operand next to it: a / b as float64 converts b alone, while -x as int64 is (-x) as int64.
What converts
| From | To | Result |
|---|---|---|
| an integer | an integer | the low bits, reinterpreted in the new type |
| an integer | a floating-point type | the nearest representable value |
| a floating-point type | an integer | truncated towards zero, saturating at the type's limits; NaN is 0 |
| a floating-point type | a floating-point type | the nearest representable value |
| a number | bool | true when the value is not zero |
bool | a number | 1 or 0 |
bool | another bool width | the same truth value |
| a character or an integer | a character or an integer | the code, as a number, or the number, as a code |
| an enum | an integer | the member's value |
| an integer | an enum | the member with that value — not checked |
| a pointer | a pointer, integer or function | see Pointers |
let big: int32 = 300;
PrintLine("{} {} {}", big as uint8, -1i32 as uint32, 200u8 as int8);
This prints 44 4294967295 -56. An integer conversion never saturates and never fails: it keeps the bits that fit.
Floating-point to integer
A float converts to an integer by truncating towards zero while the result fits. A value beyond the range saturates — one above T::Max, positive infinity included, becomes T::Max, and one below T::Min becomes T::Min — and NaN becomes 0. The rule is the same for every width, on every target, and whether the compiler folds the cast or it runs:
PrintLine("{} {} {} {}", 3.99 as int32, -3.99 as int32, 1e20 as int32, -1e20 as int32);
PrintLine("{} {}", -5.0 as uint8, float64::NaN as int32);
This prints 3 -3 2147483647 -2147483648, then 0 0: a negative value converts to 0 for an unsigned type.
bool
Any number converts to bool by testing it against zero, and a bool converts to 1 or 0:
PrintLine("{} {} {}", 5 as bool, 0 as bool, true as int32);
This prints true false 1. Where the intent is a test, a comparison says it more plainly: n != 0.
Characters
A character converts to its code, and an integer to the character with that code:
PrintLine("{} {} {}", 'A' as int32, 66 as char32, 'λ' as uint32);
This prints 65 B 955. Between character widths, the code is kept. A constant is checked against the target's range: a code that cannot exist is refused rather than wrapped.
| Cast | Error |
|---|---|
0x110000 as char32 | constant cast from 'int' to 'char32' is outside the target type's range |
-1 as char32 | constant cast from 'int' to 'char32' is outside the target type's range |
300 as char8 | constant cast from 'int' to 'char8' is outside the target type's range |
0xD800 as char32 | cast from 'int' to 'char32' uses invalid surrogate code point U+D800 |
See Characters for what each width holds.
Enums
An enum member converts to the integer it stands for, and an integer back to a member:
enum Level: uint8 {
Low = 1,
Mid = 5,
High = 9
}
PrintLine("{}", Level::Mid as int32);
let raw: uint8 = 9;
let level = raw as Level;
The conversion from an integer is not checked. A number that is no member's value gives a value that equals no member, so convert only numbers known to be valid, or test with a match on the integer first. One enum does not convert to another: Level::Low as Other is error: cannot cast enum 'Level' directly to unrelated enum 'Other'. Go through an integer when that is really meant.
What does not convert
as converts scalars. Text, structures, tuples, arrays and variants have no cast:
error: cannot cast value of type 'char8[..]' to 'int'
error: cannot cast value of type 'Point' to 'int64'
error: cannot cast variant 'Shape' to scalar type 'int32'
Parsing text into a number is a function call, not a cast — see Learn: Parse. Building a value of another type from this one is a constructor.
A sum is not narrowed with as either: value as int32 on an int32 | bool is error: cannot cast value of type 'bool8 | int32' to 'int32'. Test the member with is, and reach the value with a typed pattern.
See also
- Expressions — the conversions Rux does without
as - Integers, Floating-point types, Characters — the types converted between
- Enums — member values
- Learn: Convert, Checked convert