Optionals: Reading one safely
● Intermediate3 min
Read an optional with ?? for a default, ?. to read through, or if let to act only when it is there.
type User {
name: String
}
fn find_user(id: Int) -> User? {
if id == 7 { User(name: "Asha") } else { none }
}
fn main() {
const found = find_user(7)
const missing = find_user(8)
print(found?.name ?? "guest")
print(missing?.name ?? "guest")
if let u = find_user(7) {
print("Found {u.name}")
}
}The program ran and printed:
kavach run optionals-basic.kav
AshaguestFound Asha
There is also .unwrap(): the value, or a panic when it is none. Outside test blocks and example clauses it gets a warning, because the panic would say nothing of why:
fn find(id: Int) -> Int? {
if id == 1 { 7 } else { none }
}
fn main() {
print(find(1).unwrap())
}The compiler warned, then the program ran:
kavach run unwrap.kav
warning: `.unwrap()` panics on `none` and says nothing of why. Handle `none` with `if let`, `match` or `?? default`, or say why it can't happen: `?? panic("…")` (spec 2.7)7
Handle none with ??, ?., if let or match, or say why it can't happen with ?? panic("…"). And on a value the compiler already knows is none, .unwrap() won't even compile: see Kinds of Errors.
Optionals don't nest
A T?? is a T?. So reading an optional field through an optional value gives one none, not two: e?.time, where time is an Int?, is an Int?. It is none when there is no event, and when the event has no time:
type Event {
name: String
time: Int?
}
fn time_of(e: Event?) -> Int? {
e?.time
}
fn main() uses Console {
print(time_of(Event(name: "start", time: 5)) ?? -1)
print(time_of(Event(name: "later", time: none)) ?? -1)
print(time_of(none) ?? -1)
}The program ran and printed:
kavach run optionals-flat.kav
5-1-1