Ir para o conteúdo

Tipos ​

Primitivos ​

TipoSignificado
i8 i16 i32 i64inteiros com sinal
u8 u16 u32 u64inteiros sem sinal
f32 f64floats IEEE
booltrue / false
charum Unicode scalar value
stringtexto UTF-8 imutável, semântica de valor
OsStringbytes 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
nevero 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 ​

LiteralExemplosTipo
Inteiro42, 1_000_000, 0xFF, 0b1010i64, a menos que o contexto exija outro tipo inteiro
Float3.14, 1e-9, 2.5e3f64, 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
Booleanotrue, falsebool
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:

talor
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 ​

talor
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 value

T? é 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, mais Option, 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:

talor
let area = PI * r.powi(2);    // PI from std.math, powi a method of f64

A 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.

Talor v0.1.0 - Publicado sob a licença MIT OR Apache-2.0.