前言本文高效梳理Solidity编程语言基础知识点类型1.值类型bool(布尔):例子:boolpublic_boolintoruint(整型):例子:intpublic_intoruntpublic_uintaddress(地址):例子:address
本文高效梳理Solidity编程语言基础知识点
类型
1. 值类型
- bool(布尔):
例子: bool public _bool
- int or uint(整型):
例子:int public _int or unt public _uint
- address(地址):
例子:address public _address
- Bytes(定长字节数组):
例子:bytes32 public _byte32
- constant or immutable(常量):
# constant string public constant _string = "Hello World";
uint public immutable _string1; //需要在构造函数中初始化;
* **string (字符串)**:`string public _string`
* **enum (枚举)**:
enum ActionWeek { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, } ActionWeek action = ActionWeek.Monday function enumToUint() external view returns(uint){ return uint(action); }//返回0
### 2. 引用类型
* **Structs(结构体)**:
// 结构体 struct Student{ uint256 id; string name; unit256 age; } Student student; //赋值 //方法1 student(1,"Boykayuri",20) //方法2 student({id:1,name:"Boykayuri",age:20}) //方法3 Student storage _student = student; _student.id = 11; _student.name = "tom"; _student.age= 20; //方法4 student.id=10; student.name = "tom"; student.age= 20;
* **Array(数组)**:
uint[5] public arr1;//类型 长度
uint[] public arr1;//类型 长度
lenght//长度 push//添加 pop//删除
### 3. 映射类型
* **mapping(映射)**:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import "hardhat/console.sol"; contract mappingType { // 声明一个 mapping,键是 address,值是 bool mapping(address => bool) public hasPermission;
constructor() {
// 初始化时可以设置一些值
hasPermission[msg.sender] = true;
}
// 设置权限
function setPermission(address _address, bool _hasPermission) public {
hasPermission[_address] = _hasPermission;
}
// 检查权限
function checkPermission(address _address) public view returns (bool) {
return hasPermission[_address];
}
// 删除权限
function deletePermission(address _address) public {
delete hasPermission[_address];
}
}
# 循环和分支
* **for(循环)**:
for (unit i i<10;i++){ console.log(i) }
* **if else(分支)or 三目运算**:
if(){}else{}
条件? 条件为真的表达式:条件为假的表达式 x>=y?x:y
# 函数和事件
### 函数
**函数形式**:
`function <function name>([parameter types[, ...]]) {internal|external|public|private} [pure|view|payable] [virtual|override] [<modifiers>] [returns (<return types>)]{ <function body> }`
#### 函数说明:
* **function name**:函数名
* **[parameter types[, ...]]**:函数的参数,类型 参数
* **{internal|external|public|private}**:可见性说明符
* **[pure|view|payable]**:权限/功能的关键字
* **[virtual|override]**:是否可以被重写,或者是否是重写方法
* **modifiers**: 自定义的修饰器
* **[returns ()]**:函数返回的变量类型和名称
### 可见性修饰符
- `public`:内部和外部均可见。
- `private`:只能从本合约内部访问,继承的合约也不能使用。
- `external`:只能从合约外部访问(但内部可以通过 `this.f()` 来调用,`f`是函数名)。
- `internal`: 只能从合约内部访问,继承的合约可以用。
### 权限/功能的关键字
- `pure`:既不能读取也不能改写状态变量
- `view`:可以读取状态变量,但不能改写
- `payable`:可支付的
### 是否是重写方法
- `virtual`:用在父合约上,标识的方法可以被子合约重写
- `override`:用在自合约上,表名方法重写了父合约的方法
#### 完整代码实例
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
contract Base { function foo() public virtual returns (string memory) { return "Base foo"; }
function bar() public virtual returns (string memory) {
return "Base bar";
}
}
contract Derived is Base { function foo() public override returns (string memory) { return "Derived foo"; }
function bar() public override returns (string memory) {
return "Derived bar";
}
}
### 修饰器
modifier onlyOwner { require(msg.sender == owner); // 检查调用者是否为owner地址 _; // 如果是的话,继续运行函数主体;否则报错并revert交易 } function changeOwner(address _newOwner) external onlyOwner{ owner = _newOwner; // 只有owner地址运行这个函数,并改变owner }
### Event事件
event EventName(address indexed _addressParam, uint _uintParam, string _stringParam); 说明:indexed 关键字用于指定该参数为索引参数,允许外部应用程序通过该参数进行快速检索
emit EventName(0x4***,10,"str")
# 继承、抽象合约与接口
### 继承
contract Grandfather {
event Log(string msg); // 定义3个function: hip(), pop(), yeye(),Log值为Yeye。
function hip() public virtual{ emit Log("grandfather"); }
function pop() public virtual{ emit Log("grandfather"); }
function grandfather() public virtual { emit Log("grandfather"); }
}
contract Father is Grandfather{
// 继承两个function: hip()和pop(),输出改为father。
function hip() public virtual override{ emit Log("father"); }
function pop() public virtual override{ emit Log("father"); }
function father() public virtual{ emit Log("father"); } }
contract Boykayuri is Grandfather, Father{
// 继承两个function: hip()和pop(),输出值为boykayuri。
function hip() public virtual override(Grandfather, Father){ emit Log("boykayuri"); }
function pop() public virtual override(Grandfather, Father) { emit Log("boykayuri"); }
}
构造函数的继承
# 使用`super`关键字
contract Base {
address public owner;
constructor() {
owner = msg.sender;
}
}
contract Derived is Base { constructor() { super.constructor(); // 其他初始化代码 } }
contract Derived is Base { constructor() { Base.constructor(); // 其他初始化代码 } }
contract Derived is Base { constructor(address _owner) Base(_owner) { // 其他初始化代码 } }
### 抽象合约
- **定义**:抽象合约是一种不能被直接实例化的合约,它通常包含一些未实现的方法(抽象方法)。这些方法必须在继承抽象合约的具体合约中被实现。
- **特点**:
- **不能直接实例化**:抽象合约不能直接创建实例,只能通过继承它的具体合约来实例化。
- **包含抽象方法**:抽象合约可以包含一些没有具体实现的方法,这些方法称为抽象方法。抽象方法必须在继承抽象合约的具体合约中被实现。
- **提供接口规范**:抽象合约定义了一组方法的接口和规范,但不提供具体实现。这使得抽象合约可以作为其他合约的模板或框架。
* **abstract**:帮助开发者定义接口规范、提供通用功能以及确保合约实现特定接口
* **语法**
abstract contract Verifiable { function verify(address user) external virtual returns (bool); } contract UserContract is Verifiable { function verify(address user) external override returns (bool) { // 实现用户验证逻辑 return true; } }
### 接口
- **定义**:接口是一种特殊的合约,它只能声明方法的签名,但不能实现这些方法。接口中的所有方法都是抽象的,且不能包含任何状态变量。
- **特点**:
- **定义接口规范**:接口主要用于定义一组方法的签名,确保不同的合约实现这些方法,从而保证接口的一致性。
- **轻量级**:接口不包含任何实现,因此比抽象合约更轻量级,适合用于定义简单的接口规范。
- **互操作性**:接口可以用于不同合约之间的互操作,使得合约之间可以调用彼此的方法,而不需要知道具体的实现细节。
* **interface**:适用于定义轻量级的接口规范,确保不同合约之间的一致性,不能包含实现、状态变量、构造函数和事件
* **语法**
interface MyInterface { function myFunction() external; } contract MyContract is MyInterface { function myFunction() external { // 实现具体的功能 } }
# 变量作用域
* ### 全局变量:
**定义**:全局变量是Solidity提供的内置变量,它们可以在任何合约中直接使用,无需声明。全局变量通常用于访问区块链的某些基本信息,如区块信息、交易信息等。
**常见的全局变量**:
**block**:
- `block.number`:当前区块的编号。
- `block.timestamp`:当前区块的时间戳。
- `block.difficulty`:当前区块的难度。
- `block.gaslimit`:当前区块的气体限制。
**tx**:
- `tx.gasprice`:交易的气体价格。
- `tx.origin`:交易的发起者地址。
**msg**:
- `msg.sender`:当前消息的发送者地址。
- `msg.value`:发送给合约的以太币数量(单位为Wei)。
- `msg.data`:发送给合约的数据。
- `msg.sig`:调用函数的签名。
**abi**:
- `abi.encode`:将参数编码为字节数组。
- `abi.encodePacked`:将参数编码为紧凑的字节数组。
- `abi.encodeWithSelector`:将参数编码为字节数组,并包含函数选择器。
- `abi.decode`:将字节数组解码为指定类型的参数。
* ### 局部变量:
**定义**:局部变量是在函数内部声明的变量,它们的作用范围仅限于声明它们的函数。局部变量在函数调用时被创建,在函数返回时被销毁。
**使用案例**
pragma solidity ^0.8.0;
contract MyContract {
function myFunction() public pure {
uint256 localVariable = 42; // 局部变量
// 可以在函数内部使用 localVariable
}
}
* ### 状态变量:
**定义**:状态变量是存储在合约中的变量,它们的作用范围是整个合约。状态变量的值被永久存储在区块链上,因此它们在合约的整个生命周期中都存在
**使用案例**
pragma solidity ^0.8.0;
contract MyContract {
uint256 public stateVariable = 42; // 状态变量
function myFunction() public {
stateVariable = 100; // 修改状态变量
}
}
```
全局变量:由Solidity提供,用于访问区块链的基本信息,无需声明。
局部变量:在函数内部声明,仅在函数执行期间存在,存储在栈中。
状态变量:在合约中声明,存储在区块链上,永久存在,可以通过合约的外部调用来访问和修改。
持久性:存储在storage
中的数据是永久的,存储在区块链上。
成本:访问和修改storage
中的数据成本较高,因为每次读写操作都需要消耗Gas。
可变性:存储在storage
中的数据可以被修改。
pragma solidity ^0.8.0;
contract MyContract { uint256 public stateVariable = 42; // 存储在 storage 中
function updateStateVariable(uint256 newValue) public {
stateVariable = newValue; // 修改 storage 中的数据
}
}
### Memory(内存)
#### 特点:
- **临时性**:存储在`memory`中的数据是临时的,仅在函数调用期间存在。
- **成本**:访问和修改`memory`中的数据成本较低,因为这些操作不会写入区块链。
- **不可变性**:存储在`memory`中的数据在函数调用结束后被销毁。
#### 用法
pragma solidity ^0.8.0;
contract MyContract { function myFunction(uint256 a, uint256 b) public pure returns (uint256) { uint256 localVariable = a + b; // 存储在 memory 中 return localVariable; } }
### Calldata(调用数据)
#### 特点:
- **只读性**:存储在`calldata`中的数据是只读的,不能被修改。
- **临时性**:存储在`calldata`中的数据是临时的,仅在函数调用期间存在。
- **成本**:访问`calldata`中的数据成本较低,因为这些数据不会写入区块链。
#### 用法
pragma solidity ^0.8.0;
contract MyContract { function myFunction(uint256[] calldata values) public pure returns (uint256) { uint256 sum = 0; for (uint256 i = 0; i < values.length; i++) { sum += values[i]; } return sum; } }
### Stack(栈)
#### 特点:
- **临时性**:存储在`stack`中的数据是临时的,仅在当前操作的上下文中存在。
- **成本**:访问和修改`stack`中的数据成本极低,因为这些操作在内存中完成。
- **不可变性**:存储在`stack`中的数据在当前操作完成后被销毁。
#### 用法
pragma solidity ^0.8.0;
contract MyContract { function add(uint256 a, uint256 b) public pure returns (uint256) { uint256 result = a + b; // a 和 b 存储在 stack 中 return result; } }
### 数据存储总结
- **Storage**:永久存储在区块链上,成本高,可变。
- **Memory**:临时存储在合约执行期间的内存中,成本低,不可变。
- **Calldata**:存储在调用交易数据中的只读数据,成本低,只读。
- **Stack**:存储在执行栈中的临时数据,成本极低,不可变。
# 异常处理
- **require**:用于输入验证和状态检查,失败时返回剩余 gas 并恢复状态。
- **assert**:用于检测不变量和内部错误,失败时消耗所有剩余 gas 并恢复状态。
- **revert**:用于显示抛出异常,支持携带错误信息,失败时返回剩余 gas 并恢复状态。
- **自定义错误**:从 Solidity 0.8.4 开始引入,使用 error 关键字定义,通过 revert 抛出,节省 gas 并提高代码可读性。
- **事件日志**:用于记录错误信息,便于后续查询和调试。
### 使用方法说明:
* **require**
require(false,"错误信息描述");//判断条件为false
* **assert**:
assert(true)//判断条件为true
* **自定义异常**
error TransferNotOwner(address sender); if(true){ revert TransferNotOwner(msg.sender); }
# 总结
以上内容对Solidity的基础要点进行了梳理。如需深入了解,可查阅Solidity官方文档。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!