1. Types có giá trị
1.1. INT / UINT
uint là viết tắt của unsigned integer, có nghĩa là số nguyên không âm và bạn có thể lựa chọn kích thước của nó từ uint8 đến uint256
uint8
bắt đầu từ0
tới2 ** 8 - 1
uint16
bắt đầu từ0
tới2 ** 16 - 1
...uint256
bắt đầu từ0
to2 ** 256 - 1
uint8 public u8 = 1;
uint256 public u256 = 456;
uint public u = 123; // uint là viết tắt của uint256
int là viết tắt của integer, có nghĩa là số nguyên âm và không âm và bạn có thể lựa chọn kích thước của nó từ int8 đến int256
int8
bắt đầu từ-2 ** 7
tới2 ** 7 - 1
int16
bắt đầu từ-2 ** 15
tới2 ** 15 - 1
...int128
bắt đầu từ-2 ** 127
tới2 ** 127 - 1
int256
bắt đầu từ-2 ** 255 tới 2
**255 - 1
int8 public i8 = -1;
int256 public i256 = 456;
int public i = -123; // int là viết tắt của int256
Toán tử của int và uint:
- So sánh: <=, <, ==, !=, >=, > (trả về
bool
) - Toán tử Bit: &, |, ^ (bitwise exclusive hoặc), ~ (bitwise negation)
- Toán tử Shift: << (left shift), >> (right shift)
- Toán tử số học: +, -, dấu âm - (chỉ cho
signed integer
), *, /, % (phép toán modulo), ** (hàm mũ)
Cho một biến X type integer
, bạn có thể dùng type(X).min
và type(X).max để truy cập giá trị bé nhất và lớn nhất có thể diễn tả bằng type đó.
// minimum and maximum of int type:
int public minInt = type(int).min;
int public maxInt = type(int).max;
// minimum and maximum of uint type:
uint public minUint = type(uint).min;
uint public maxUint = type(uint).max;
1.2. BOOL
bool có nghĩa là Boolean và có 2 giá trị true và false
bool public trueVar = true;
bool public falseVar = false;
1.3. Toán tử:
!
(luận lý ngược, tương đương “not”)&&
(luận lý gộp tương đương “and”)||
(luận lý hoặc tương đương “or”)==
(bằng)!=
(không bằng)
Toán tử ||
và &&
áp dụng các quy tắc short-circuit thông thường. Điều này có nghĩa là trong biểu thức f(x) || g(y)
, nếu f(x)
đánh giá là true
, g(y)
sẽ không được đánh giá ngay cả khi nó có thể có tác động phụ.
1.4. ADDRESS
address
là một kiểu dữ liệu đặc biệt trong Solidity cho phép lưu trữ 20 byte (kích cỡ) địa chỉ của một tài khoản Ethereumaddress payable
tương tự vớiaddress
nhưng có thêm tính năngtransfer
vàsend
address public exampleAddress = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;
address payable public examplePayableAddress = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;
1.5. BYTES
Trong Solidity, kiểu dữ liệu byte đại diện cho một chuỗi byte. Solidity có hai loại kiểu bytes:
- Array byte có kích thước cố định
- Array byte có kích thước động.
Từ bytes trong Solidity đại diện cho một Array động của byte. Căn bản là viết tắt của byte[]
.
bytes1 a = 0xb5; // [10110101]
bytes1 b = 0x56; // [01010110]
bytes c = "abc"; // [01100001, 01100010, 01100011]
1.6. Giá trị mặc định
Những biến được khai báo mà không gán giá trị thì sẽ có giá trị mặc định
bool public defaultBool; // false
uint public defaultUint; // 0
int public defaultInt; // 0
address public defaultAddr; // 0x0000000000000000000000000000000000000000
bytes1 public defaultByte; // 0x00
1.7. CONTRACT
contract được dùng để khai báo 1 contract trong solidity
contract HelloWorld {}
contract cũng có thể thừa hưởng từ 1 contract khác với keyword is
contract Mercedes is Car {}
1.8. ENUM
Enum
là một cách để tạo kiểu do người dùng xác định trong Solidity. Chúng có thể chuyển đổi rõ ràng sang và từ tất cả các loại số nguyên nhưng không được phép chuyển đổi ngầm. Việc chuyển đổi rõ ràng từ số nguyên sẽ kiểm tra trong thời gian chạy rằng giá trị nằm trong phạm vi của enum và gây ra Panic Error
nếu không. Enums
yêu cầu ít nhất một thành viên và giá trị mặc định của nó khi được khai báo là thành viên đầu tiên. Enums
không thể có nhiều hơn 256 thành viên.
Cách biểu diễn dữ liệu giống như đối với enum trong C: Các tùy chọn được biểu thị bằng các giá trị số nguyên không dấu tiếp theo bắt đầu từ 0.
Sử dụng type(NameOfEnum).min
và type(NameOfEnum).max
bạn có thể nhận được giá trị nhỏ nhất và lớn nhất tương ứng của enum đã cho.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Enum {
// Enum representing shipping status
enum Status {
Pending,
Shipped,
Accepted,
Rejected,
Canceled
}
// Default value is the first element listed in
// definition of the type, in this case "Pending"
Status public status;
// Returns uint
// Pending - 0
// Shipped - 1
// Accepted - 2
// Rejected - 3
// Canceled - 4
function get() public view returns (Status) {
return status;
}
// Update status by passing uint into input
function set(Status _status) public {
status = _status;
}
// You can update to a specific enum like this
function cancel() public {
status = Status.Canceled;
}
// delete resets the enum to its first value, 0
function reset() public {
delete status;
}
}
1.9. TYPE
Loại giá trị do người dùng xác định cho phép tạo ra sự trừu tượng hóa chi phí bằng 0 đối với loại giá trị cơ bản. Điều này tương tự như bí danh nhưng có yêu cầu loại chặt chẽ hơn.
Loại giá trị do người dùng xác định được xác định bằng loại type C is V
, trong đó C
là tên của loại type mới được khai báo và V
phải là loại giá trị tích hợp.
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.8;
// Represent a 18 decimal, 256 bit wide fixed point type using a user-defined value type.
type UFixed256x18 is uint256;
1.10. FUNCTION
function
dùng để khai báo 1 hàm trong solidity.
Mình khai báo 1 function
đầy đủ như bên dưới
contract Counter {
uint public count;
// Hàm để xem biến count
function get() public view returns (uint) {
return count;
}
}
2. Reference types
2.1. Vị trí lưu Data
Các biến được khai báo cùng với các từ storage
, memory
hoặc calldata
để chỉ định vị trí lưu dữ liệu.
storage
- biến là state variable (lưu trên blockchain)memory
- biến ở trong memory và chỉ tồn tại khifunction
đang hoạt độngcalldata
- nơi lưu trữ dữ liệu đặc biệt có chứa dữ liệu truyền vào function
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DataLocations {
uint storage varStorage
uint memory varMemory
uint calldata varCallData
}
2.2. Array
Array là tổ hợp các phần tử giá trị giống định dạng của nhau, tương tự như list trong python và array trong Javascript.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Array {
// Several ways to initialize an array
uint[] public arr;
uint[] public arr2 = [1, 2, 3];
// Fixed sized array, all elements initialize to 0
uint[10] public myFixedSizeArr;
function get(uint i) public view returns (uint) {
return arr[i];
}
// Solidity can return the entire array.
// But this function should be avoided for
// arrays that can grow indefinitely in length.
function getArr() public view returns (uint[] memory) {
return arr;
}
function push(uint i) public {
// Append to array
// This will increase the array length by 1.
arr.push(i);
}
function pop() public {
// Remove last element from array
// This will decrease the array length by 1
arr.pop();
}
function getLength() public view returns (uint) {
return arr.length;
}
function remove(uint index) public {
// Delete does not change the array length.
// It resets the value at index to it's default value,
// in this case 0
delete arr[index];
}
function examples() external {
// create array in memory, only fixed size can be created
uint[] memory a = new uint[](5);
}
}
2.3. Struct
Struct là định dạng dữ liệu mà lập trình viên khai báo để gom nhiều biến có định dạng khác nhau lại dưới 1 tên gọi để dễ dàng sử dụng trong contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Todos {
struct Todo {
string text;
bool completed;
}
// An array of 'Todo' structs
Todo[] public todos;
function create(string calldata _text) public {
// 3 ways to initialize a struct
// - calling it like a function
todos.push(Todo(_text, false));
// key value mapping
todos.push(Todo({text: _text, completed: false}));
// initialize an empty struct and then update it
Todo memory todo;
todo.text = _text;
// todo.completed initialized to false
todos.push(todo);
}
// Solidity automatically created a getter for 'todos' so
// you don't actually need this function.
function get(uint _index) public view returns (string memory text, bool completed) {
Todo storage todo = todos[_index];
return (todo.text, todo.completed);
}
// update text
function updateText(uint _index, string calldata _text) public {
Todo storage todo = todos[_index];
todo.text = _text;
}
// update completed
function toggleCompleted(uint _index) public {
Todo storage todo = todos[_index];
todo.completed = !todo.completed;
}
}
3. Mapping Types
Mapping
mapping
được sử dụng để tạo 1 hashmap
(tương tự như dict
trong python
) giữa 1 type với 1 type khác.
Lưu ý:
Khi bạn tạo 1 mapping, tất cả các key đều tồn tại. Điều này nghĩa:
Ví dụ bạn tạomapping(address => uint256) addressToValue;
. Nếu bạn chưa thay đổikey
vàvalue
nào thì hiện tại tất cảaddress
bạn nhập vào sẽ trả về giá trị mặc định củauint256
là bằng 0.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Mapping {
// Mapping from address to uint
mapping(address => uint) public myMap;
function get(address _addr) public view returns (uint) {
// Mapping always returns a value.
// If the value was never set, it will return the default value.
return myMap[_addr];
}
function set(address _addr, uint _i) public {
// Update the value at this address
myMap[_addr] = _i;
}
function remove(address _addr) public {
// Reset the value to the default value.
delete myMap[_addr];
}
}
contract NestedMapping {
// Nested mapping (mapping from address to another mapping)
mapping(address => mapping(uint => bool)) public nested;
function get(address _addr1, uint _i) public view returns (bool) {
// You can get values from a nested mapping
// even when it is not initialized
return nested[_addr1][_i];
}
function set(address _addr1, uint _i, bool _boo) public {
nested[_addr1][_i] = _boo;
}
function remove(address _addr1, uint _i) public {
delete nested[_addr1][_i];
}
}
4. Simple Storage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SimpleStorage {
// Declare a variable to store the name of the maintainer
string public maintainerName = "zxstim";
// Declare the version of the contract
uint8 public version = 1;
// Declare an address to receive donation
address public donationAddress = 0xe3d25540BA6CED36a0ED5ce899b99B5963f43d3F;
// Declare a Person type to store information of a person
struct Person {
string name; // name
uint8 age; // age
bool overEighteen; // Over eighteen?
address uuid; // UUID
uint256 assetValue; // asset value
int256 debtValue; // debt value
}
Person[] private listOfPeople; // this syntax means creating an array to store Person named listOfPeople
mapping(address => Person) uuidToPerson; // this syntax means creating a mapping from address to Person named uuidToPerson
// this function will store the information of a new person with name, age, overEighteen, assetValue, debtValue
function storePerson(string memory _name, uint8 _age, bool _overEighteen, uint256 _assetValue, int256 _debtValue) public returns (Person memory person) {
_assetValue *= 1e18; // Convert asset value to wei unit
_debtValue *= 1e18; // Convert debt value to wei unit
// Add information of the new person to the listOfPeople array
listOfPeople.push(Person({name: _name, age: _age, overEighteen: _overEighteen, uuid: msg.sender, assetValue: _assetValue, debtValue: _debtValue}));
// Add information of the new person to the uuidToPerson mapping
uuidToPerson[msg.sender] = Person({name: _name, age: _age, overEighteen: _overEighteen, uuid: msg.sender, assetValue: _assetValue, debtValue: _debtValue});
return Person({name: _name, age: _age, overEighteen: _overEighteen, uuid: msg.sender, assetValue: _assetValue, debtValue: _debtValue});
}
// this function will retrieve the information of a person based on the address
function retrievePerson(address _address) public view returns (Person memory person) {
return uuidToPerson[_address];
}
}