bool
int
/uint
int8
toint256
in steps of 8uint8
touint256
in steps of 8
fixed
/ufixed
fixedMxN
/ufixedMxN
:M
must be divisible by 8 and goes from 8 to 256 bits.N
must be between 0 and 80.
address
bytes1
,bytes2
,bytes3
, ...,bytes32
aliases:
int
is alias forint256
uint
is alias foruint256
fixed
is alias forfixed128x18
ufixed
is alias forufixed128x18
byte
is alias forbytes1
arrays
bytes
: Dynamically-sized byte array.string
: Dynamically-sized UTF-8-encoded string.
structs
Complex types, i.e. types which do not always fit into 256 bits have to be handled more carefully than the value-types. Since copying them can be quite expensive, we have to think about whether we want them to be stored in memory
(which is not persisting) or storage
(where the state variables are held).
Every complex type, i.e. arrays and structs, has an additional annotation, the "data location", about whether it is stored in memory or in storage.
Only complex data types (arrays and structs) default to storage inside functions, while all others default to memory.
memory
- A byte-array
- Contiguous
- Starts off zero-size, but can be expanded in 32-byte chunks by simply accessing or storing memory at indices greater than its current size
- Not persisted across external function calls
storage
- A key/value store where keys and values are both 32 bytes
- Sparse
- Persisted
calldata
- Not modifiable.
- Not persisted.
- Function arguments are stored.
- Behaves mostly like memory.
Depending on the context, there is always a default, but it can be overridden by appending either storage or memory to the type. The default for function parameters (including return parameters) is memory, the default for local variables(complex type) is storage and the location is forced to storage for state variables (obviously).
Only complex data types (arrays and structs) default to storage inside functions, while all others default to memory.
Storage is a key/value store where keys and values are both 32 bytes. Memory is a byte-array. Memory starts off zero-size, but can be expanded in 32-byte chunks by simply accessing or storing memory at indices greater than its current size.
- Forced data location:
- parameters (not return) of external functions: calldata
- state variables: storage
- Default data location:
- parameters (also return) of functions: memory
- all other local variables: storage
- literal array and string: storage(assigned to state variable) / memory(assigned to local variable)
Assignments between storage and memory always create an independent copy.
pragma solidity ^0.4.21;
contract DataLocation {
int[] myArray = [0, 0]; // ok: storage = storage
string myString= "Solidity"; // ok: storage = storage
function DataLocation(uint index, int value){
myArray[index] = value;
int[] myArray2 = myArray; // ok: storage = storage
uint16[3] memory myArray3= [1, 2, 9999]; // ok: memory = memory
uint8[2] myArray4= [1,2]; // error: storage = memory
string myString2= myString; // ok: storage = storage
string memory myString3= "ABCDE"; // ok: memory = memory
myString3= "XYZ"; // ok: memory = memory
string myString4= "Example"; // error: storage = memory
}
}
Array literals are always statically-sized memory arrays.
Complex local variables are not "held in storage" at all, they are always a reference to some state variable. This is the case in the below example of a complex local variable:
contract Thingy {
uint256[] stateArray;
function doStuff() public {
// By default solidity will create the below as a `storage reference`
// This is the same as declaring as:
// uint256[] storage localReference = stateArray;
// This is essentially a pointer to the state variable's storage location
uint256[] localReference = stateArray;
// If it is required that the array only exists locally,
// one must explicitly state that the variable is to be
// held in memory
uint256[] memory memArray = new uint256[](5);
}
}
Due to the difference in the implementation of storage and memory, local complex variables (declared memory) must have a compile-time fixed size. Storage variables can be of dynamic size