Solidity 8.0 初阶-基础语法
类型和值
// 常用变量
bool public b = true;
uint public u = 123; // uint = uint256 0~2**256 -1
// uint 8 = 0~ 2**8 -1
int public i = -123;
int public minInt = type(int).min;
int public maxInt = type(int).max;
address public addr = 0x0eF3E974d17C21e42B40909445B134480Df1Aa6F;
bytes32 public b32 = 0x0909445B13440eF3E974d17C21e42B40909445B134480Df1Aa6F3234532345;
函数介绍
contract HelloWord {
// external 外部函数,只能在外部读取,能出现在 abi 中
// pure 不读也不写(只能有局部变量)
function add(uint x, uint y) external pure returns(uint){
return x + y;
}
function sub(uint x, uint y) external pure returns(uint){
return x - y;
}
}
变量
- 局部变量 函数内变量
- 全局变量
- 状态变量(链上变量)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract HelloWord {
// 状态变量(链上变量)
uint public myUint = 123;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract HelloWord {
// 常见的全局变量
// view 可以读取全局变量和状态变量, pure 只能读取局部变量
function globalCars() external view returns(address, uint, uint) {
address sender = msg.sender;
uint timestamp = block.timestamp; // 区块时间戳(只读的)
uint blockNum = block.number; // 区块
return (sender, timestamp, blockNum);
}
}
只读函数
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
// view 和 pure 区别
// 如果要改写变量,这不能填写 view或者pure
contract HelloWord {
uint public num;
// 因为该函数读取了,状态变量(链上变量)只能用 view 来定义
function viewFunc() external view returns (uint){
return num;
}
// 只读取局部变量用 pure
function pureFunc(uint x, uint y) external pure returns (uint) {
return x + y;
}
// 对链上变量进行改写,就能用 view 来修饰了
function inc() external {
num -= 1;
}
}
常量
:::info
constant 可以修饰变量,让其变为常量,不能修改其值,节约 gas 费用
:::
// constant 修饰变量位常量,且命名规范位大写
address public constant MY_ADDRESS = 0x0eF3E974d17C21e42B40909445B134480Df1Aa6F;
uint public constant MY_UINT = 123;
返回值
contract FunctionOutputs {
// 返回方法1
function retrunMany() public pure returns(uint, bool) {
return (1, true);
}
// 返回方法2
function assigned() public pure returns (uint x, bool b){
x = 1;
b = true;
}
// 接收返回值
function destructing() public pure {
(uint x, bool b) = retrunMany(); // 接受2个返回值
(, bool _b) = retrunMany(); // 只要第二个返回值
}
}
判断
普通判断与三元运算
if(_x<10){
return 1;
}else if(_x<20){
return 2;
}
// 三元运算
return _x < 10 ? 1:2;
循环
function loops() external pure{
for (uint i=0; i<10; i++){
if (i==3){
continue; // break;
}
}
uint j = 0;
while (j < 10){
j++;
}
}
报错
- 8.0 版本之前 通常用 require, revert, assert
- 8.0后用 error 定义
// 报错控制
contract Error {
// require, revert, assert 都需要 gas 费
function testRequire(uint _i) public pure{
require(_i <= 10, "Test: i > 10");
}
function testRevert(uint _i) public pure {
if(_i > 10) { // 大于 10 就进行报错
revert("i > 10");
}
}
// assert 断言
uint public num = 123;
function testAssert() public view {
assert(num == 123);
}
// 8.0+可以自定义错误
error MyError(address caller, uint i); // 定义在顶部可以给当前文件使用
function testError(uint _i) public view{
if (_i > 10){
revert MyError(msg.sender, _i);
}
}
}
数组
contract Array {
uint[] public nums = [1,2,3,4]; // 动态数组
uint[3] public numsFixed = [1,2,3]; // 定长数组
// 数组
function examples() external {
nums.push(9); // 末尾推入一个新的值
uint x = nums[1]; // 访问指定下标,从0开始
nums[2] = 777; // 修改
delete nums[1]; // 删除下标位置元素,值改为默认值 uint 默认 0 (总长度不变) 想要实现真正删除,只能直接写remove例子在下面
nums.pop(); //弹出最后一个元素(会删除)
uint len = nums.length; // 获取长度
// 内存中创建数组
// 只能定义定长数组,且不能 pop, push
uint[] memory a = new uint[](5);
}
// 通过函数返回数组的全部类容
function returnArray() external view returns(uint[] memory){
return nums;
}
// [1,2,3] -- remove(1) -- [1,3] 删除元素
uint[] public arr = [1,2,3];
function remove(uint _index) public {
require(_index < arr.length, "index out of bound");
for (uint i = _index; i < arr.length -1; i++){
arr[i] = arr[i+1];
}
arr.pop();
}
}
类型-映射 (json)
映射就相当于 json
// 映射(json)
contract Mapping{
// 声明映射: 地址映射余额
mapping(address => uint) public balances; // 查找地址,余额就会返回
// 嵌套映射, 查找2个地址是否是朋友关系
mapping(address => mapping(address => bool)) public isFirend;
function examples() external{
balances[msg.sender] = 123; // 设置映射值
uint bal = balances[msg.sender]; // 获取映射值
delete balances[msg.sender]; // 删除后,等于默认值 0
// 设置嵌套映射
isFirend[msg.sender][address(this)] = true; // {address1: {address2: true}}
}
}
获取迭代映射数据
contract IterableMapping {
mapping(address => uint) public balances; // 地址对应余额
mapping(address => bool) public inserted; // 地址是否存在映射中
address[] public keys; // 所有地址
// 设置
function set(address _key, uint _val) external{
balances[_key] = _val;
if (!inserted[_key]){
inserted[_key] = true;
keys.push(_key);
}
}
function getSize() external view returns (uint){
return keys.length;
}
// 查询第一个
function first() external view returns(uint) {
return balances[keys[0]];
}
// 查询最后一个
function last() external view returns(uint){
return balances[keys[keys.length-1]];
}
// 获取指定位置
function get(uint _i) external view returns(uint){
return balances[keys[_i]];
}
}
类型-结构体(对象)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
// 结构体
contract Structs{
struct Car { // 汽车对象结构体
string model;
uint year;
address owner;
}
Car public car; // 定义一个变量
Car[] public cars; // 定义一个数组
mapping(address => Car[]) public carsByOwner; // 定义一个 映射 json,一个地址可能有多个汽车
function examples() external {
// 生成结构体方法1
Car memory toyota = Car("Toyota", 1990, msg.sender);
// 方法2
Car memory lambo = Car({model:"Lamborghini", year: 1980, owner:msg.sender});
// 方法3
Car memory tesla; // 默认值
tesla.year = 2020;
tesla.model = "Tesla";
tesla.owner = msg.sender;
// 推入结构体数组 2 种方法
cars.push(toyota);
cars.push(lambo);
cars.push(tesla);
cars.push(Car("Ferrari", 1943, msg.sender));
// 获取局部变量值
Car memory _car = cars[0];
_car.model;
// 结构体可以定义在内存中 memory
// 也可以定义在 存储中 (就可以进行修改和删除操作)
Car storage _car2 = cars[0];
_car2.year = 1888; // 存储中才能进行修改
delete _car2.owner; // 删除(清空为默认值)
delete cars[1]; // 删除,都是清空为默认值
}
}
类型-枚举
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
// 枚举类型
contract Enum {
enum Status { // 例子:枚举 当前操作的状态
None, // 空
Pending,// 处理中
Shipped,// 装载中
Completed, // 已装载
Rejected, // 已拒绝
Canceled // 已取消
}
Status public status;
struct Order { // 结构体
address buyer;
Status status;
}
Order[] public orders;
// 操作枚举类型
function get() public view returns (Status){ // 读取
return status;
}
function set(Status _status) external {
status = _status;
// status= Status.Shipped; // 也可以直接设置为指定值
}
function reset() external{ // 状态变量恢复到默认值 (第一个值)
delete status;
}
}
Hash 运算
abi.encode()
采用 abi 的编码形式补0 【推荐使用】abi.encodePacked()
只是把字符串变成了16进制
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
contract HashFunc {
// 建议使用 encode 标准模式打包
function hash(string memory text, uint num, address addr) external pure returns(bytes32){
return keccak256(abi.encodePacked(text, num, addr));
}
// 举例两种打包模式的区别
function encode(string memory text, string memory text2) external pure returns(bytes memory){
return abi.encode(text, text2);
}
function encodePacked(string memory text, string memory text2) external pure returns(bytes memory){
return abi.encodePacked(text, text2);
}
}
// 测试: hellow,222,0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!