Expressions and operators
Literals, the operator set, casts, the try operator and the pipe.
Literals
function examples(): i32 {
let a: i32 = 42;
let b: f64 = 3.14;
let c: boolean = true;
let d: char = 'a';
let e: str = "hello";
let f: i32 = 0xFF;
let g: i32 = 0b1010;
let h: atom = :ok;
let i: i32[3] = [1, 2, 3];
return a;
}
A numeric literal adapts to the type the context asks for, as long as the value fits: let a: u8 = 255; is fine and let x: u8 = 256; is a compile-time error. Float literals move between f32 and
f64 the same way.
Same-sign integers widen implicitly — u8 through u64, i8 through i64 — so assigning a u8
to a u32 needs no cast. Crossing signs does: u8 to i32 requires an explicit as.
Template literals
A backtick literal builds an owned String, and ${ } drops an expression into the surrounding
text.
let banner: String = `hello ${name} v${version}`;
See Template literals for slots, escapes, what a slot accepts, and why interpolating a variable does not move it.
Operators
| Group | Operators |
|---|---|
| Arithmetic | + - * / % |
| Comparison | == != < > <= >= |
| Logical | && || ! |
| Bitwise | & | ^ ~ << >> |
| Assignment | = += -= *= /= %= &= |= ^= <<= >>= |
| Increment | x++ x-- ++x --x |
| Cast | expr as Type |
| Pipe | |> |
| Try | expr! |
| Ternary | cond ? a : b |
Casts
function main(): i32 {
let value: i32 = 42;
let a: i64 = 42 as i64;
let p: *i32 = &value as *i32;
return a as i32;
}
The try operator
Postfix ! unwraps the success variant of a @lang(try) enum, or returns the failure variant from
the enclosing function.
@lang(try)
enum Result<T, E> {
OK(T),
ERROR(E),
}
function divide(a: i32, b: i32): Result<i32, str> {
if (b == 0) {
return Result::ERROR("division by zero");
}
return Result::OK(a / b);
}
function compute(): Result<i32, str> {
let x = divide(10, 2)!;
let y = divide(20, 4)!;
return Result::OK(x + y);
}
expr! is shorthand for a match: the success arm yields the payload, the failure arm returns the
failure variant unchanged. Three conditions have to hold — the expression’s type is a @lang(try)
enum, the function’s return type is compatible with it, and the error type matches exactly. That
last one is the usual reason a ! refuses to compile.
The pipe operator
lhs |> rhs passes the left value as the first argument to the call on the right, and it is
left-associative.
import Io from "std::io";
import String from "std::string";
function add(x: i32, y: i32): i32 {
return x + y;
}
function main(): i32 {
add(2, 3)
|> String::create
|> Io::println;
return 0;
}
Ternary
function pick(x: i32, isReady: boolean): i32 {
let a: i32 = isReady ? 1 : 0;
let b: i32 = x > 10 ? x : 10;
return a + b;
}