Reference Data Types

Learn about the features and uses of reference data types.

Reference data types

Reference data types don’t hold value directly; instead, they store the location of the data. With the help of reference types, two different variables can refer to the same location, and any modification made in one variable can affect the other one. We’ll demonstrate this soon. There are a number of reference types; let’s take a look at them.

Strings and bytes

Strings and bytes are special types of arrays in Solidity. The bytes type is used to store a fixed-sized character set, while the string data type is used to store a character set equal to or more than a byte. The string type is equal to bytes but doesn’t allow us to check its length or index access. This means that unlike in other languages, in Solidity we cannot use string.length to check for the length of a string or string[3] to get the character at index 3. However, this is possible with bytes. The bytes type also has the advantage of using less gas, so it’s better to use it when we know the data length. Increments go from bytes1 to bytes32. Here’s how we can initialize strings and bytes in Solidity using string literals:

string testString = "hello"; // using double quotes
string testString2 = 'hello'; // using single quotes
string testString3 = 'hello' "world"; // same as "helloworld"
// bytes
bytes testBytes = "Any length of data";
bytes1 testBytes2 = "a"; // just one char
bytes5 testBytes3 = "abcde"; // 5 char
bytes32 testBytes4 = "Any length of data up to 32 characters";
Code sample demonstrating different ways to initialize strings

Strings and bytes can be concatenated by using string.concat(str1, str2, ...otherStr) or bytes.concat(byte1, byte2, ...otherBytes). We can also convert from string to bytes and vice versa if we need to.

Structs

Structs in Solidity give us the ability to define new data types. Here, we can structure a new type that defines properties that can be of different types. This structure is a reference type variable that can include both value and reference. To define a new struct, we use the keyword struct. Let’s demonstrate this using our Contacts contract.

Press + to interact
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Contact
* @dev Store & retrieve contacts of friends and family
*/
contract Contact {
enum Relationship {
Family,
Friend,
Acquaintance
}
struct ContactDetail {
uint256 number;
string name;
address payable _address;
bool isEmergencyContact;
Relationship relationship;
}
address owner;
constructor() {
owner = msg.sender;
}
/**
* @dev Save new contact
* @param number_ number of contact to store
* @param name_ name of contact to store
* @param address_ blockchain address of contact to store
* @param relationship_ relationship of contact to store
*/
function save(uint256 number_, string calldata name_, address payable address_, Relationship relationship_) public {
// save contact
}
}

Instead of defining the various properties of a contact as global variables, we put them all in one new type we structured called ContactDetail. This makes it easier ...