Tipos
Primitivos
| Tipo | Significado |
|---|---|
i8 i16 i32 i64 | inteiros com sinal |
u8 u16 u32 u64 | inteiros sem sinal |
f32 f64 | floats IEEE |
bool | true / false |
char | um Unicode scalar value |
string | texto UTF-8 imutável, semântica de valor |
OsString | bytes que não precisam ser UTF-8, um nome dado pelo sistema operacional, semântica de valor |
() | unit; void é a grafia dele em posição de retorno |
never | o tipo de uma expressão que não retorna (panic, return, break) |
Todos os primitivos exceto string são Copy. string é cheap-clone: o compilador pode copiá-la implicitamente, porque uma cópia é um retain.
O subconjunto de bootstrap (Core v0) implementa i32 i64 u8 f64 bool char string () never.
Literais
| Literal | Exemplos | Tipo |
|---|---|---|
| Inteiro | 42, 1_000_000, 0xFF, 0b1010 | i64, a menos que o contexto exija outro tipo inteiro |
| Float | 3.14, 1e-9, 2.5e3 | f64, a menos que o contexto exija f32 |
| String | "text", escapes \n \t \r \\ \" \0 \u{1F600} | string |
| Template | `x = ${expr}` | string |
| Char | 'a', '\n', '\u{41}' | char |
| Booleano | true, false | bool |
| Unit | () | () |
Não existe literal null: a ausência de um valor é None. Um literal inteiro é lido como 64 bits e checado contra o tipo em que é escrito, então um valor que não cabe é recusado em vez de truncado.
Aritmética
Os operandos de um operador têm o mesmo tipo: não há widening implícito entre tipos inteiros, nem entre inteiros e floats. i64 + i32 é um erro; escreva a + (b as i64). A divisão inteira trunca em direção a zero. Um overflow gera panic, e um build com --release faz wrap em vez disso.
Conversões
as converte entre tipos numéricos, de char para inteiro e de bool para inteiro. Qualquer outra coisa é um erro. Um inteiro vira um char por meio de char.of(n), que responde None para um número que não é um Unicode scalar value:
fn main(): i32 {
let big: i64 = 300;
let low = big as u8; // 44: the low eight bits
let code = 'A' as i64; // 65
let half = 7 as f64 / 2.0; // 3.5
let letter = match char.of(66) { Some(c) => c, None => '?' };
println(`${low} ${code} ${half} ${letter}`);
0
}Compostos
Array<T> // growable array, owned
Option<T> // Some(T) | None
Result<T, E> // Ok(T) | Err(E)
Box<T> // owned heap value
shared T // a counted allocation: `.clone()` retains, `*r` reads, read-only
dyn Trait // any type implementing Trait, method chosen at run time
Map<K, V> // hash map, from std
(A, B) // tuple; fields t.0, t.1
fn(A): R // function valueT? é açúcar sintático para Option<T>, permitido em qualquer lugar onde um tipo é escrito. Argumentos generic se aninham sem limite: Option<Array<Token>>, Map<string, Array<i64>>.
Um tipo tupla tem no máximo 16 elementos. Uma tupla tem o layout de uma struct com um campo por elemento.
O que é copiado, o que passa por move
Três classes decidem tudo sobre atribuição e chamadas:
- Copy: todo primitivo exceto
string, tuplas de tipos Copy, e structs ou variants cujas partes são todas Copy. Copiados na atribuição e na chamada, livremente. - Plain: Copy, mais
string, maisOption,Result, tuplas, structs e variants feitos só de tipos plain. Copiados implicitamente onde uma cópia é o que o programa precisa; passam por move em vez disso quando a cópia seria o último uso. - Todo o resto (
Array,Box,shared,Map,fn, e qualquer tipo que contenha um deles): passa por move. Veja ownership.
Floats: os métodos de f64
f64 tem os métodos do Rust: uma raiz, uma potência ou um logaritmo é um método do valor, um limite é um static do tipo, e as constantes matemáticas ficam em std.math:
let area = PI * r.powi(2); // PI from std.math, powi a method of f64A lista completa, e o que um float responde nos seus extremos, está em Matemática.
Nominal, não estrutural
Duas structs com os mesmos campos são tipos diferentes. Um type alias (type Id = i64;) é um nome novo, não um tipo novo.