Optional Chaining
Nullable member access with the `?.` operator.
Nullable types use ?, and optional member access uses ?..
struct Z {
val: i32,
}
struct Y {
z: Z?,
}
struct X {
y: Y?,
}
fn main() {
let x: X? = X { y: Y { z: Z { val: 42 } } };
let v: i32? = x?.y?.z?.val;
assert v != null;
let missing: X? = null;
let none: i32? = missing?.y?.z?.val;
assert none == null;
}
Use ?. for each nullable hop. If any receiver in the chain is null, the
whole chain yields null and later member lookups are skipped.
The result type is nullable even when the final field is not nullable:
struct User {
name: str,
}
fn main() {
let user: User? = User { name: "Ada" };
let name: str? = user?.name;
assert name != null;
}
The compiler diagnoses mixed chains that try to continue through nullable
values with plain .:
let bad = x?.y.z;
Write x?.y?.z when y is nullable too.
Optional chaining handles nullable success values only. It does not unwrap
throws(...) results. Handle the error first with try or catch, then use
?. on the nullable value:
error UserError {
Missing
}
struct User {
name: str,
}
fn load_user(id: i32) throws(UserError) -> User? {
if id == 0 {
return null;
}
return User { name: "Ada" };
}
fn main() {
let loaded: str? = (try load_user(1))?.name;
let fallback: str? = (load_user(0) catch { _ => null })?.name;
assert loaded != null;
assert fallback == null;
}
For T? throws(E), try yields T?, and catch arms may return either T
or null.