Definition

Khi sử dụng các kiểu dữ liệu tham chiếu (struct, array và mapping), chúng ta phải khai báo một cách tường minh vị trí lưu trữ (data location) của biến.

Có ba loại data location là:

  • storage: là các biến được lưu vĩnh viễn ở trên blockchain (có thể xem như lưu vào ổ cứng).
  • memory: là các biến tạm thời, sẽ được xóa bỏ giữa các lần gọi hàm (có thể xem như lưu vào RAM).
  • calldata: giống như memory nhưng không thể sửa đổi. Location này chỉ có thể được dùng để lưu các đối số của các hàm external1. Nói một cách đơn giản, chúng lưu các dữ liệu được gửi đến từ người dùng hoặc smart contract.

Tất cả các state variable và các biến có kiểu tham chiếu (struct, array hoặc mapping) ở trong hàm sẽ có data location mặc định là storage. Trong khi đó, các biến có kiểu tham trị ở trong hàm sẽ có data location mặc định là memory và sẽ được giải phóng khi function được thực thi xong2.

Ví dụ minh họa:

pragma solidity ^0.8.0;
 
contract DataLocationExample {
    uint private privateVariable; // storage
    uint[] public storageArray; // storage
 
    function modifyData(uint[] memory memoryArray, uint[] calldata calldataArray) public {
        // Rest of the function code...
    }
}

Đối với các tham số có kiểu dữ liệu tham chiếu, ta nên sử dụng data location là memory.

Convention

Chúng ta nên đặt tên tham số bắt đầu bằng ký tự _. Cách đặt tên này giúp phân biệt các biến tham số với các biến toàn cục.

calldata Vs memory

Từ khóa calldata là danh cho các tham số không thể thay đổi giá trị. Trong khi đó, memory là dành cho các tham số mà có thể thay đổi giá trị. Để chỉnh sửa các biến calldata, nó cần phải được load vào memory.

Note

Đa số các kiểu dữ liệu có storage location mặc định là memory. Tuy nhiên, đối với string, ta cần chỉ định cụ thể memory hoặc calldata do cách mà mảng được xử lý trong bộ nhớ

string memory variableName = "someValue";

Các biến calldata là read-only và có chi phí rẻ hơn memory. Trong ví dụ bên dưới, nếu chúng ta cố gán giá trị cho biến calldata thì sẽ nhận lỗi:

function addPerson(string calldata _name, uint256 _favoriteNumber) public {
    _name = "cat";
    listOfPeople.push(Person(_favoriteNumber, _name));
}

Ngoài ra, ta chỉ có thể specify storage location cho các biến không thuộc kiểu primitive:

Cite

Data location can only be specified for array, struct, or mapping type

Do đó, việc gán memory cho kiểu uint256 như bên dưới sẽ sinh ra lỗi:

Footnotes

  1. Xem thêm Solidity - Visibility.

  2. Tham khảo Solidity - Why are local variables allocated to storage instead of memory? - Ethereum Stack Exchange