Hi @Talk2coded,
Sorry for the delay in getting back to you.
The values stored in an array are ordered according to a fixed sequence of indices (0,1, 2, 3 etc.). Each index number and its associated value is a key/value pair (each unique key being an index number). This means that, as well as being able to reference or retrieve values by their specific index number (if we know it), arrays can also be iterated over. The ability to iterate over an array, means we can search for specifc data stored within it, without needing to know specific index numbers (keys).
The reason why the syntax for an array declaration is simpler than that of a mapping is because we don’t need to define the data type of the keys: these are always a sequence of ascending uint
values starting with 0
(and automatically set for us). The data type of the values to be stored in the array at each index is declared immediately preceding the square brackets e.g.
uint[] arrayOfUnsignedIntegers;
string[] arrayOfStrings;
Person[] arrayOfStructInstances;
/* This will hold struct instances (similar to objects) which are created
based on the template of properties defined in the Person struct */
The square brackets declare the state variable as an array (in the same way that the keyword mapping
declares those as mappings). Then, apart from the name/identifier (which is placed at the end of the declaration, the only other keywords that might be needed to define a storage array are those marking the visibility as public
or private
. Unlike functions (where a visibility keyword must be included in the declaration) state variables have a default visibility of internal
, which means that if the visibility is not explicitly stated (as in the 3 examples above) it will be internal
by default.
Mappings are also data structures which store key/value pairs. However, unlike arrays, values can be mapped to unique keys of data types other than uint
e.g. addresses or strings. There is, therefore, no need for values to be added and stored in a mapping according to a fixed, sequential order of integers which must begin with 0
.
The syntax for looking up values in a mapping which are mapped to data types other than addresses is exactly the same as the syntax used with addresses. As with arrays, we reference a value stored in a mapping with the mapping name followed by the key in square brackets e.g.
uint[] numbers;
mapping(uint => uint) balances;
mapping(address => string) names;
// Assuming that these 3 data structures already contain values...
function getNumber(uint index) view public returns(uint) {
return numbers[index];
}
function getBalance(uint id) view public returns(uint) {
return balances[id];
}
function getName() view public returns(string memory) {
return names[msg.sender];
}
Unless a mapping is defined with uint
keys, and the values are added and mapped according to a fixed sequence of uint
keys which mirror an array’s index values, mappings cannot be iterated over. In Solidity, mappings are commonly used to map values to Ethereum addresses. In order to add, modify, reference or retrieve a value mapped to an address, this unique address needs to be known. This gives mappings the ability to provide more in-built data privacy than arrays.
Generally speaking, if you need to store and look up large amounts of data, using mappings will be more efficient than using arrays, and will save you a noticeable amount of gas. With large amounts of data, using arrays, where mappings could provide the same results, runs the risk of transactions running out of gas and failing, because the gas limit has been reached.
I hope this gives you a clearer picture of mappings and arrays in Solidity.