Option sugar can be added to simplify destructuring of members that are optional. This will also be used in function arguments to evaluate non-static expressions.
For non-static expressions left expressions, where ‘[]’ is optional, the parsing rules are:
Foo { ([member:] [ref] [mut] var [= empty_value]),+ , [..] }
- The type of the member must be an enum of type Option
- The struct name and brackets are mandatory
- Member is optional only if the variable name matches member name
- At least one member must be specified
The type must be Option because it needs to …:
- … be an enum
- … be unwrappable
- … have an empty variant
- … be declared in the struct (Result is not suitable)
Since there is only one value to unwrap, this leaves us with Option as the only candidate.
// No unwrap
let Foo {x, ..} = foo;
// Unwrap with default
let Foo {x = 3, ..} = foo;
The reason struct name is mandatory is because the compiler would not be able to infer the type otherwise. An alternative syntax is to leave out the struct name but require a type annotation.
Whenever the left argument type is Option, a right argument expression which type is not Option desugars to ‘Some(value)’.
let x: Option<uint> = 3;
When a struct takes no generic arguments, the type annotation is optional.
struct Bar { x: Option<uint> }
fn foo(Bar { x }) { ... } // No unwrap
fn foo(Bar { x = 3 }) { ... } // Unwrap with default
foo(x: 2)
foo(x: Some(2))
Option is the only type with a fixed default value, which is None. It is not possible to override this in struct definition. This is to avoid ambiguity.
struct Bar { x: Option<uint>, y: Option<uint> }
fn foo(Bar { x = 3, .. }) { ... } // Ignore y
fn foo(Bar { x = 3, y }) { ... }
When taking a struct by reference, the type annotation is required.
fn foo(&self, &Bar { ref mut x = 3, ref y }: &mut Bar) { ... }
Non-static expressions when unwrapping by default in functions, but must depend only on arguments before. This is to avoid cyclic dependencies.
// y depends on x
fn foo(Bar { x = 3, y = x + 2 }) { ... }
// y depends on self
fn foo(&self, Bar { x = 0, y = self.len() } { ... }
A non-static expression can use brackets to execute arbitrary code.