Types
Every variable, item, and value in a Rust program has a type. The type of a value defines the interpretation of the memory holding it and the operations that may be performed on the value.
Built-in types are tightly integrated into the language, in nontrivial ways that are not possible to emulate in user-defined types. User-defined types have limited capabilities.
The list of types is:
- Primitive types:
- Sequence types:
- User-defined types:
- Function types:
- Pointer types:
- Trait types:
Type expressions
Syntax
Type :
TypeNoBounds
| ImplTraitType
| TraitObjectTypeTypeNoBounds :
ParenthesizedType
| ImplTraitTypeOneBound
| TraitObjectTypeOneBound
| TypePath
| TupleType
| NeverType
| RawPointerType
| ReferenceType
| ArrayType
| SliceType
| InferredType
| QualifiedPathInType
| BareFunctionType
| MacroInvocation
A type expression as defined in the Type grammar rule above is the syntax for referring to a type. It may refer to:
- Sequence types (tuple, array, slice).
- Type paths which can reference:
- Pointer types (reference, raw pointer, function pointer).
- The inferred type which asks the compiler to determine the type.
- Parentheses which are used for disambiguation.
- Trait types: Trait objects and impl trait.
- The never type.
- Macros which expand to a type expression.
Parenthesized types
ParenthesizedType :
(
Type)
In some situations the combination of types may be ambiguous. Use parentheses
around a type to avoid ambiguity. For example, the +
operator for type
boundaries within a reference type is unclear where the
boundary applies, so the use of parentheses is required. Grammar rules that
require this disambiguation use the TypeNoBounds rule instead of
Type.
#![allow(unused)] fn main() { use std::any::Any; type T<'a> = &'a (dyn Any + Send); }
Recursive types
Nominal types — structs, enumerations, and unions — may be
recursive. That is, each enum
variant or struct
or union
field may
refer, directly or indirectly, to the enclosing enum
or struct
type
itself. Such recursion has restrictions:
- Recursive types must include a nominal type in the recursion (not mere type
aliases, or other structural types such as arrays or tuples). So
type Rec = &'static [Rec]
is not allowed. - The size of a recursive type must be finite; in other words the recursive fields of the type must be pointer types.
- Recursive type definitions can cross module boundaries, but not module visibility boundaries, or crate boundaries (in order to simplify the module system and type checker).
An example of a recursive type and its use:
#![allow(unused)] fn main() { enum List<T> { Nil, Cons(T, Box<List<T>>) } let a: List<i32> = List::Cons(7, Box::new(List::Cons(13, Box::new(List::Nil)))); }