proc main(): void {
v := ["a", "b", "c"]
echo v[2] // um literal em um tamanho conhecido
last := len(v) - 1
if v bounds last {
echo v[last] // a guarda cobre
}
if v bounds last && v[last] == "c" {
echo "e o resto da própria condição"
}
for i := 0; i < len(v); i++ {
echo v[i] // a condição do laço é a guarda
}
if indexOf(v, "b") is Result.Ok(at) {
echo v[at] // uma posição que indexOf respondeu
}
}func cell(t: Str[dyn][dyn], r: Int, c: Int): Str {
// `if t bounds r { if t[r] bounds c { echo t[r][c] } }` é recusado:
// t[r] é uma linha diferente a cada vez que r muda, então ela é vinculada antes.
if t bounds r {
row := t[r]
if row bounds c {
return row[c]
}
}
return ""
}
proc main(): void {
Str[dyn][dyn] t = [["a", "b"], ["c", "d"]]
echo cell(t, 1, 0)
}Todo índice e toda fatia são provados dentro dos limites antes de o programa rodar, então nenhum pode falhar quando ele roda; um que o compilador não consegue provar é um erro de compilação. O que prova um:
v[2] em um Str[3].if v bounds i { … }, que é i >= 0 && i < len(v). Ela cobre o ramo abaixo dela e o resto da sua própria condição com &&, então if v bounds i && v[i] > 0 fica provado; ela não prova nada depois de um ||.len(v).indexOf respondeu — mas só para o vetor que ele procurou.O que não prova nada: um índice calculado na hora, como v[len(v) - 1], que precisa ser vinculado a um nome e guardado; um return antecipado, já que uma guarda prova só o ramo que abre; e uma célula de uma linha escolhida por um índice que muda, t[r][c], em que a linha precisa ser vinculada antes — row := t[r] — e a célula guardada contra ela. Os dois limites de uma fatia são provados um de cada vez.
Uma prova dura até algo poder mudar aquilo de que ela trata: atribuir ao vetor ou ao índice, declarar qualquer um de novo ou vincular o nome dele em um padrão, drop (o único builtin que encurta um vetor), ou passar o vetor a um parâmetro mut. Dentro de um laço, o que o corpo faz conta para toda volta.