Ir para o conteúdo

Fluxo de controle ​

if, e o bloco, são expressões ​

talor
let sign = if x < 0 { -1 } else if x == 0 { 0 } else { 1 };
let v = { let t = compute(); t * 2 };

O valor de um bloco é a sua expressão final; sem uma, o bloco tem tipo (). Um if usado como valor precisa ter um else, e os dois ramos precisam ter o mesmo tipo. Condições são bool; não são exigidos parênteses em volta delas.

Loops ​

talor
fn count_up(n: i64): i64 {
    let i: i64 = 0;
    while i < n {
        i += 1;
    }
    i
}
talor
// `loop` runs until something breaks out of it.
fn first_power_of_two_over(limit: i64): i64 {
    let v: i64 = 1;
    loop {
        if v > limit { break; }
        v = v * 2;
    }
    v
}
talor
fn sum_below(n: i64): i64 {
    let total: i64 = 0;
    for i in 0..n {             // half-open integer range, only in `for`
        total = total + i;
    }
    total
}

fn letters(text: string): i64 {
    let n: i64 = 0;
    for c in text {             // the characters of a string, decoded
        n += 1;
    }
    n
}

Um for sobre um array produz os seus elementos, e tanto for quanto let recebem um padrão, então uma tupla é desmontada onde é feito o binding:

talor
fn main(): i32 {
    let scores = [("ana", 7), ("bia", 9)];
    let best = 0;
    for (name, score) in scores {
        if score > best { best = score; }
        println(`${name} scored ${score}`);
    }
    let (low, high) = (1, best);
    println(`${low} to ${high}`);
    0
}

Um elemento de um array que a função não possui é um borrow no corpo do loop, não uma cópia.

break e continue agem sobre o loop em que estão escritos, e return sai da função. Chaves são obrigatórias em todo corpo. switch, do/while, o for (;;) no estilo de C, goto e breaks com rótulo não existem.

match ​

talor
let area = match shape {
    Shape.Circle(r) => r * r * PI,
    Shape.Rect { w, h } => w * h,
    Shape.Empty => 0.0,
};

match token.kind {
    TokenKind.Plus | TokenKind.Minus => { /* the body */ }     // or-pattern
    TokenKind.Integer(n) if n > 100 => { /* the body */ }      // guard
    _ => { }                                         // wildcard
}
PadrãoCasa com
_qualquer coisa, sem binding
namequalquer coisa, e faz o binding dela
literal (1, 'a', "s", true)valor igual
Enum.Variant, Enum.Variant(p, q), Enum.Variant { f: p, g }aquela variant, com sub-padrões no payload
Some(p), None, Ok(p), Err(p)os casos de Option e Result
(p, q)tupla
Struct { f: p, g }destructuring de struct
p | qqualquer um dos dois padrões; as duas alternativas precisam fazer binding dos mesmos nomes, e quando fazem binding, a alternância fica no topo de um arm (Case(a) | Case(b)), nunca dentro de um payload
p if condpadrão mais guard, só no topo de um arm

Três regras dão ao match a sua segurança:

  • Todo match é exaustivo. Um match não exaustivo é um erro de compilação.
  • Um arm que nenhum valor alcança também é um erro. Um nome sozinho é o padrão que faz binding, não uma comparação: match os { OS_LINUX => ..., _ => ... } com duas constantes faz o binding de OS_LINUX e deixa dois arms inalcançáveis. O jeito de comparar com uma constante é if os == OS_LINUX.
  • Bindings fazem borrow. Um nome que um padrão liga se refere ao lugar casado pela duração do arm: payloads Copy são copiados, todo outro payload é lido no lugar. Guardar, retornar ou passar um nome ligado a um parâmetro takes é um move, e borrowing diz quando isso é permitido.

Arms são separados por ,; um arm com bloco não precisa de vírgula. Todos os corpos dos arms precisam ter o mesmo tipo quando o match é usado como valor.

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