References
It is possible to create references to objects, i.e. resources or structures. A reference can be used to access fields and call functions on the referenced object.
References are copied, i.e. they are value types.
References are created by using the &
operator, followed by the object,
the as
keyword, and the type through which they should be accessed.
The given type must be a supertype of the referenced object's type.
References have the type &T
, where T
is the type of the referenced object.
_12let hello = "Hello"_12_12// Create a reference to the "Hello" string, typed as a `String`_12//_12let helloRef: &String = &hello as &String_12_12helloRef.length // is `5`_12_12// Invalid: Cannot create a reference to `hello`_12// typed as `&Int`, as it has type `String`_12//_12let intRef: &Int = &hello as &Int
If you attempt to reference an optional value, you will receive an optional reference. If the referenced value is nil, the reference itself will be nil. If the referenced value exists, then forcing the optional reference will yield a reference to that value:
_10let nilValue: String? = nil_10let nilRef = &nilValue as &String? // r has type &String?_10let n = nilRef! // error, forced nil value_10_10let strValue: String? = ""_10let strRef = &strValue as &String? // r has type &String?_10let n = strRef! // n has type &String
References are covariant in their base types.
For example, &T
is a subtype of &U
, if T
is a subtype of U
.
_35_35// Declare a resource interface named `HasCount`,_35// that has a field `count`_35//_35resource interface HasCount {_35 count: Int_35}_35_35// Declare a resource named `Counter` that conforms to `HasCount`_35//_35resource Counter: HasCount {_35 pub var count: Int_35_35 pub init(count: Int) {_35 self.count = count_35 }_35_35 pub fun increment() {_35 self.count = self.count + 1_35 }_35}_35_35// Create a new instance of the resource type `Counter`_35// and create a reference to it, typed as `&Counter`,_35// so the reference allows access to all fields and functions_35// of the counter_35//_35let counter <- create Counter(count: 42)_35let counterRef: &Counter = &counter as &Counter_35_35counterRef.count // is `42`_35_35counterRef.increment()_35_35counterRef.count // is `43`
References may be authorized or unauthorized.
Authorized references have the auth
modifier, i.e. the full syntax is auth &T
,
whereas unauthorized references do not have a modifier.
Authorized references can be freely upcasted and downcasted, whereas unauthorized references can only be upcasted. Also, authorized references are subtypes of unauthorized references.
_39_39// Create an unauthorized reference to the counter,_39// typed with the restricted type `&{HasCount}`,_39// i.e. some resource that conforms to the `HasCount` interface_39//_39let countRef: &{HasCount} = &counter as &{HasCount}_39_39countRef.count // is `43`_39_39// Invalid: The function `increment` is not available_39// for the type `&{HasCount}`_39//_39countRef.increment()_39_39// Invalid: Cannot conditionally downcast to reference type `&Counter`,_39// as the reference `countRef` is unauthorized._39//_39// The counter value has type `Counter`, which is a subtype of `{HasCount}`,_39// but as the reference is unauthorized, the cast is not allowed._39// It is not possible to "look under the covers"_39//_39let counterRef2: &Counter = countRef as? &Counter_39_39// Create an authorized reference to the counter,_39// again with the restricted type `{HasCount}`, i.e. some resource_39// that conforms to the `HasCount` interface_39//_39let authCountRef: auth &{HasCount} = &counter as auth &{HasCount}_39_39// Conditionally downcast to reference type `&Counter`._39// This is valid, because the reference `authCountRef` is authorized_39//_39let counterRef3: &Counter = authCountRef as? &Counter_39_39counterRef3.count // is `43`_39_39counterRef3.increment()_39_39counterRef3.count // is `44`
References are ephemeral, i.e they cannot be stored. Instead, consider storing a capability and borrowing it when needed.