https://aptos.dev/img/meta/og-aptos-docs-default.png

Move programs can create, delete, and update resources in global storage using the following five instructions:

Operation Description Aborts?
move_to<T>(&signer,T) Publish T under signer.address If signer.address already holds a T
move_from<T>(address): T Remove T from address and return it If address does not hold a T
borrow_global_mut<T>(address): &mut T Return a mutable reference to the T stored under address If address does not hold a T
borrow_global<T>(address): &T Return an immutable reference to the T stored under address If address does not hold a T
exists<T>(address): bool Return true if a T is stored under address Never

Each of these instructions is parameterized by a type T with the key ability. However, each type T must be declared in the current module. This ensures that a resource can only be manipulated via the API exposed by its defining module. The instructions also take either an address or &signer representing the account address where the resource of type T is stored.

References to resources​

References to global resources returned by borrow_global or borrow_global_mut mostly behave like references to local storage: they can be extended, read, and written using ordinary reference operators and passed as arguments to other function. However, there is one important difference between local and global references: a function cannot return a reference that points into global storage. For example, these two functions will each fail to compile:

struct R has key { f: u64 }// will not compilefun ret_direct_resource_ref_bad(a: address): &R {    borrow_global<R>(a) // error!}// also will not compilefun ret_resource_field_ref_bad(a: address): &u64 {    &borrow_global<R>(a).f // error!}

Move must enforce this restriction to guarantee absence of dangling references to global storage. This section contains much more detail for the interested reader.

Global storage operators with generics​

Global storage operations can be applied to generic resources with both instantiated and uninstantiated generic type parameters:

struct Container<T> has key { t: T }// Publish a Container storing a type T of the caller's choosingfun publish_generic_container<T>(account: &signer, t: T) {    move_to<Container<T>>(account, Container { t })}/// Publish a container storing a u64fun publish_instantiated_generic_container(account: &signer, t: u64) {    move_to<Container<u64>>(account, Container { t })}

The ability to index into global storage via a type parameter chosen at runtime is a powerful Move feature known as storage polymorphism. For more on the design patterns enabled by this feature, see Move generics.

Example: Counter​

The simple Counter module below exercises each of the five global storage operators. The API exposed by this module allows: