A struct is a user-defined data structure containing typed fields. Structs can store any non-reference type, including other structs.
A resource is a kind of struct that cannot be copied and cannot be dropped. All resource values must have ownership transferred by the end of the function. Resources are used to define global storage schemas, and Only resource structs can be saved directly into global storage.
Structs must be defined inside a module:
Structs cannot be recursive, so the following definition is invalid:
Struct definitions can be annotated with the
resource modifier, which imposes a few additional constraints on the type, but also enables it to be used in global storage. We will cover the details later in this tutorial.
Note: the term
resource struct is a little bit cumbersome so in many places we just call it
Structs must start with a capital letter
Z. After the first letter, constant names can contain underscores
Z, or digits
This naming restriction of starting with
Z is in place to give room for future language features. It may or may not be removed later.
Values of a struct type can be created (or "packed") by indicating the struct name, followed by value for each field:
If you initialize a struct field with a local variable whose name is the same as the field, you can use the following shorthand:
This is called sometimes called "field name punning".
Struct values can be destroyed by binding or assigning them patterns.
&mut operator can be used to create references to structs or fields. These examples include some optional type annotations (e.g.,
:& Foo) to demonstrate the type of operations.
It is possible to borrow inner fields of nested structs.
You can also borrow a field via a reference to a struct.
If you need to read and copy a field's value, you can then dereference the borrowed field
If the field is an implicitly copyable, the dot operator can be used to read fields of a struct without any borrowing.
Dot operators can be chained to access nested fields.
However, this is not permitted for fields that contain non-primitive types, such a vector or another struct
The reason behind this design decision is that copying a vector or another struct might be an expensive operation. It is important for a programmer to be aware of this copy and make others aware with the explicit syntax
In addition reading from fields, the dot syntax can be used to modify fields, regardless of the field being a primitive type or some other struct
The dot syntax also works via a reference to a struct
Most struct operations on a struct type
T can only be performed inside the module that declares
- Struct types can only be created ("packed"), destroyed ("unpacked") inside the module that defines the struct.
- The fields of a struct are only accessible inside the module that defines the struct.
Following these rules, if you want to modify your struct outside the module, you will need to provide publis APIs for them. The end of the chapter contains some examples of this.
However, struct types are always visible to another module or script:
Note that structs do not have visibility modifiers (e.g.,
By default, structs can be freely copied and silently dropped.
Resource structs on the other hand, cannot be copied or dropped silently. This property can be very useful when modeling real world resources like money, as you do not want money to be duplicated or get lost in circulation.
To fix the second example (
fun dropping_resource), you will need to manually "unpack" the resource:
In addition, in order to enforce the said ownership rules at all times, it is required that normal structs do NOT have contain fields of resource types.
Recall that you are only able to deconstruct a resource within the module in which it is defined. This can be leveraged to enforce certain invariants in a system, for eaxmple, conservation of money.