Pointers
Pointers in Spawn are similar to the references described earlier. Their behavior is as close as possible to pointers in C, which means that they are unsafe by default, but are still efficient and can be used to work with external libraries.
Unlike references, pointers can be null. The nil keyword is used to represent
a null pointer. Although null pointers are usually described as unsafe,
using nil does not require an unsafe block, since the presence of a null
pointer itself is not dangerous, only to dereference of a null pointer, which
requires an unsafe block, is dangerous.
Create a pointer
To create a pointer, as for references, the & and &mut operators are used,
which are explicitly cast to the pointer type:
In this example, we create a pointer to a variable number of type i32 by
taking a reference to it using the & operator and explicitly casting it to the
pointer type *i32. This is the only way to create pointers in Spawn.
nil pointers do not have an explicit type, so when using nil as a value when
creating a variable, you must explicitly specify the type:
Dereference
As with references, the * operator is used to access the value pointed to by a
pointer. However, the compiler cannot be sure that the pointer is valid, so
pointer dereference is an unsafe operation and must be done in an unsafe
block:
Modify the value by pointer
As with references, the * operator is used to change the value of a pointer:
However, there is no automatic dereferencing for pointers, and changing the
value of a pointer is an unsafe operation and must be done in an unsafe block.
Pointer arithmetic
As in C, pointers can be modified using arithmetic operations. To understand what pointer arithmetic is, let's look at the following example:
In this small example, we allocate memory for three values of type i32 using
the alloc function from the mem module, which returns a reference to the
allocated memory, since references don't support arithmetic, we explicitly cast
it to a pointer type *i32 .
Now let's look at what an allocated memory block looks like:
___________________
| 1 | 2 | 3 |
|_____|_____|_____|
^
ptr
The ptr variable stores the address of the first element. In the first line of
the unsafe block we write the value 10 to this address:
___________________
| 1 | 2 | 3 |
|_ _|_ _|_ _|
| 10 | | |
|_____|_____|_____|
^
ptr
In the second line we write the value, but at an address equal to the address of
the first element plus the size of one element. Note that +1 means shift by
one element, not one byte.
___________________
| 1 | 2 | 3 |
|_ _|_ _|_ _|
| 10 | 20 | |
|_____|_____|_____|
^ ^ ptr + 1
ptr
And finally on the third line we get the value at ptr + 1, which is 20.
Be careful, if you try to write a value to address ptr + 200, the program will
likely crash with a segmentation fault because you are trying to write a value
to memory that has not been allocated.
The entry *(ptr + X) can be written in the more readable form ptr[X]:
Pointer arithmetic is defined only for array-like pointers, which are shown above, and for pointers to structure elements; otherwise the behavior is undefined.