Patterns in bindings and conditions
A pattern also stands after const and var, in the head of if and while, and in a for loop - the same vocabulary as a match arm, without the braces.
match is not the only place a pattern stands. const, var, if, while and for all take one, and the same
rules of Pattern forms apply - the difference is what happens when the pattern does not match.
Example#
fn firstPositive(numbers: List<Int>): Int? {
if const Some(first) = numbers.find({ _ > 0 }) {
return first
}
None
}
print firstPositive([-1, -2, 3, 4])Syntax#
const <pattern> [: <Type>] = <expression> binds; the pattern has to match every value of that type
var <pattern> [: <Type>] = <expression> the same, and the names it binds are `var`
for <pattern> in <expression> { ... } binds for one iteration; the pattern has to match every item
if const <pattern> = <expression> { ... } the names bind only inside the block, only if the pattern matches
if var <pattern> = <place> { ... } binds into the place instead of into a copy; see `if var`
while const <pattern> = <expression> { ... } re-evaluates and re-matches before every iterationRules#
if constandwhile constbind their names only for the body, and only when the pattern matches. They read like amatchwith exactly one arm and an implicitelsethat skips the body (if) or ends the loop (while).fn describe(id: Int, findUser: (id: Int) => String?): String { if const Some(name) = findUser(id) { return name } "no such user" }constandvarare irrefutable positions: the pattern has to match every value of the type it is given, or the checker reports one it does not. A pattern that can fail belongs in amatchor anif constinstead.Does not compilefn firstOf(pairs: List<(Int, Int)>): Int { const [first] = pairs first.0 } print firstOf([(1, 2)]) // error: The pattern of a binding has to match every value, and `[]` does notA bare case name is such a pattern too, and it looks the most like a declaration:
const None = valueis the patternNone, not a constant calledNone, and it can fail.Does not compilefn probe(value: Int?) { const None = value } // error: The pattern of a binding has to match every value, and `.Some(_)` does notA name that is no case in scope is the constant it looks like, and then the finding is about its spelling (
A constant starts with a lowercase letter: writelimit``), because a constant starts with a lowercase letter.A tuple has exactly one shape, so a tuple pattern is irrefutable there, and a case pattern is irrefutable for a type with exactly one constructor. Both bind directly after
const/var, without amatch. So does a list pattern of anArray<Item, Size>with exactlySizeitems, or with a rest and at mostSizeitems around it: the length of an array is in its type, as the arity of a tuple is (Pattern forms, rule 11). AListis not such a type - its length is a value, and rule 2 shows what the checker says.type Point { x: Int y: Int } fn run() { const (quotient, remainder) = (7 / 2, 7 % 2) const Point(x, y) = Point 3, 4 const corners: Array<Int, 3> = [1, 2, 3] const [first, second, third] = corners print "{quotient} {remainder} {x} {y} {first + second + third}" } run()The variable of a
forloop is a pattern too, and it has to match every item of what is iterated.for (key, value) in someMapdestructures each entry; a pattern that only some items match is the same error as rule 2, naming"item"instead of"value".fn total(pairs: Map<String, Int>): Int { var sum = 0 for (key, value) in pairs { sum = sum + value } sum } print total(["a": 1, "b": 2])The name a
forloop binds isconstfor the duration of one iteration. To change an element in place, writefor var item in items, whose name is the slot and a single name, never a pattern that takes the element apart (Changing elements in place) - or use a path into the collection (items[index].x = 1).
What this is not#
A pattern at the top level of an entry file or a script is not different from one inside a function. const (a, b) = pair and const Point(x, y) = point declare their names exactly as rule 3 shows, whether they stand inside a
function body or directly at the top level of an entry file or a script. A module's own top level is the exception:
its const binds one name, never a pattern (see Top-level code).
if const is not if let used for control flow on its own; the condition still has to be a pattern that can fail.
A pattern that always matches belongs after a plain const, and the checker says so instead of accepting a binding
that could have been a match with one arm:
fn run() {
if const value = 3 {
print value
}
}
run()
// error: This pattern always matches. Use `const`Related#
- Pattern forms - every pattern this page reuses.
- Exhaustiveness - the algorithm behind "has to match every value".
- if var - binding into a place instead of into a copy.
- Bindings -
constandvarthemselves, and the module exception noted there.