Trong Solidity, bytes, bytes1, và string đều dùng để lưu trữ dữ liệu, nhưng chúng có những khác biệt quan trọng về kích thước, cách sử dụng và chi phí gas.
Về cơ bản, bytes1 là kiểu dữ liệu có kích thước cố định chỉ 1 byte. bytes là một mảng byte có kích thước động, phù hợp cho dữ liệu nhị phân thô. string cũng là một mảng có kích thước động nhưng được thiết kế đặc biệt cho dữ liệu văn bản được mã hóa theo chuẩn UTF-8.
| Tính năng | bytes | bytes1 (và bytes2…bytes32) | string |
|---|---|---|---|
| Loại dữ liệu | Mảng byte thô | Mảng byte thô | Chuỗi ký tự mã hóa UTF-8 |
| Kích thước | Động (có thể thay đổi) | Cố định (1 đến 32 bytes) | Động (có thể thay đổi) |
| Tính thay đổi (Mutability) | Có thể thay đổi (Mutable) | Không thể thay đổi trực tiếp từng phần tử (Immutable) | Không thể thay đổi (Immutable) |
| Truy cập phần tử | Có thể truy cập theo chỉ số (ví dụ: data[0]) | Có thể truy cập theo chỉ số | Không thể truy cập theo chỉ số |
| Lấy độ dài | Có thuộc tính .length | Có thuộc tính .length (luôn trả về kích thước cố định) | Phải chuyển đổi sang bytes để lấy độ dài |
| Chi phí Gas | Tương đối thấp. Hiệu quả cho dữ liệu động. | Rất thấp. Hiệu quả nhất cho dữ liệu có kích thước nhỏ và cố định. | Cao hơn bytes do xử lý mã hóa UTF-8. |
| Trường hợp sử dụng | Dữ liệu nhị phân có độ dài bất kỳ, dữ liệu thô từ các hàm hash. | Dữ liệu ngắn, có kích thước cố định (ví dụ: mã lỗi, cờ trạng thái). | Dữ liệu văn bản dành cho người đọc (ví dụ: tên, mô tả). |
Details
bytes
Đây là một mảng byte có kích thước động, tương tự như byte[]. Nó được coi là lựa chọn ưu tiên khi bạn cần xử lý dữ liệu nhị phân thô mà không biết trước độ dài.
- Tính linh hoạt: Bạn có thể dễ dàng lấy độ dài của mảng bằng
data.lengthvà truy cập từng byte riêng lẻ bằng chỉ số, ví dụdata[i]. - Tối ưu Gas: Khi xử lý dữ liệu có độ dài thay đổi,
bytesthường tiết kiệm gas hơnstring.
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract BytesExample {
bytes public myBytes;
function setBytes(bytes memory _data) public {
myBytes = _data;
}
function getLength() public view returns (uint) {
return myBytes.length;
}
function getFirstByte() public view returns (bytes1) {
return myBytes[0];
}
}bytes1 To bytes32
Đây là các kiểu dữ liệu có kích thước cố định, trong đó con số phía sau chỉ định số lượng byte. Ví dụ, bytes1 lưu trữ 1 byte, bytes32 lưu trữ 32 bytes. Kiểu byte là một tên gọi khác (alias) của bytes1.
- Hiệu quả về Gas: Vì EVM (Máy ảo Ethereum) hoạt động với các từ (words) 32 byte, việc sử dụng
bytes1đếnbytes32rất hiệu quả về mặt chi phí lưu trữ và xử lý. Nếu dữ liệu của bạn có kích thước nhỏ hơn hoặc bằng 32 byte, hãy luôn ưu tiên sử dụng các kiểu này. - Hạn chế: Chúng có kích thước cố định và không thể thay đổi độ dài sau khi đã khai báo.
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract BytesFixedExample {
bytes32 public myData; // Có thể lưu trữ một chuỗi 32 ký tự ASCII
function setData(bytes32 _data) public {
myData = _data;
}
}string
string là một kiểu dữ liệu có kích thước động được thiết kế đặc biệt để lưu trữ văn bản được mã hóa UTF-8.
- Tính bất biến (Immutable): Một khi đã được tạo, bạn không thể thay đổi các ký tự riêng lẻ của một chuỗi. Bất kỳ sự sửa đổi nào cũng sẽ tạo ra một chuỗi hoàn toàn mới.
- Hạn chế truy cập: Solidity không hỗ trợ truy cập trực tiếp vào các ký tự của chuỗi bằng chỉ số (ví dụ:
myString[0]là không hợp lệ). Để thao tác với chuỗi (như lấy độ dài hoặc ký tự cụ thể), bạn phải chuyển đổi nó sangbytes. - Chi phí Gas: Thường tốn kém hơn
bytesdo chi phí xử lý mã hóa UTF-8.
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract StringExample {
string public myString;
function setString(string memory _message) public {
myString = _message;
}
// Phải chuyển đổi sang bytes để lấy độ dài
function getLength() public view returns (uint) {
return bytes(myString).length;
}
}Advices💡
- Nếu dữ liệu của bạn có độ dài cố định và nhỏ hơn hoặc bằng 32 byte, hãy dùng
bytes1đếnbytes32để tiết kiệm gas tối đa. - Nếu bạn cần xử lý dữ liệu nhị phân thô có độ dài thay đổi, hãy dùng
bytes. - Chỉ sử dụng
stringkhi bạn thực sự cần lưu trữ dữ liệu văn bản (dành cho người đọc) và chấp nhận chi phí gas cao hơn. Trong nhiều trường hợp, việc lưubytesvà chuyển đổi thành chuỗi ở phía client (giao diện người dùng) sẽ hiệu quả hơn.