solidity基础语法
:::tip 导航
solidity教程
:::
在编写sol文件之前要加上
1 | // SPDX-License-Identifier: MIT |
或者
1 | // SPDX-License-Identifier: SimPL-3.0 |
数据类型
特殊变量/全局变量,是全局可用的变量
Solidity 特殊变量/全局变量

Solidity 变量作用域
局部变量的作用域仅限于定义它们的函数,但是状态变量可以有四种作用域类型:
- public – 公共状态变量可以在内部访问,也可以从外部访问。对于公共状态变量,将自动生成一个 getter 函数。
- private – 私有状态变量只能从当前合约内部访问,派生合约内不能访问。
- internal – 内部状态变量只能从当前合约或其派生合约内访问。
- external - 外部状态变量只能在合约之外调用 ,不能被合约内的其他函数调用。
Solidity 条件运算符
? : (条件运算符 )
如果条件为真 ? 则取值X : 否则值Y
1 | function getResult() public pure returns(uint){ |
输出结果
1 | { |
循环语句
while循环
1 | function whilexunhuan(uint loop) public pure returns (uint) { |
for循环
1 | function forXunhuan(uint loop) public pure returns (uint) { |
do-while循环
1 | function doWhileXunhuan(uint loop) public pure returns (uint) { |
pure和view
solidity pure函数,也就是纯函数,是指函数不会读取或修改状态。
换言之,solidity pure函数不会操作链上数据。
solidity view函数,也就是视图函数,是指函数只会读取状态,不会修改状态。
换言之,solidity view函数只会读取链上数据,不会修改链上数据。
构造函数
Solidity构造函数是一个特殊函数,它仅能在智能合约部署的时候调用一次,之后就不能再次被调用。
Solidity构造函数常用来进行状态变量的初始化工作。
Solidity编译器中,使用关键词 constructor 作为构造函数。
1 | uint public user; |
onlyOwner修饰符
1 | /** |
Solidity 加密函数
- keccak256(bytes memory) returns (bytes32) 计算输入的Keccak-256散列。
- sha256(bytes memory) returns (bytes32) 计算输入的SHA-256散列。
- ripemd160(bytes memory) returns (bytes20) 计算输入的RIPEMD-160散列。
- ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) 从椭圆曲线签名中恢复与公钥相关的地址,或在出错时返回零。函数参数对应于签名的ECDSA值: r – 签名的前32字节; s: 签名的第二个32字节; v: 签名的最后一个字节。这个方法返回一个地址。
keccak256加密
1 | function callkeccak256(string memory a) public pure returns (bytes memory) { |
Solidity 不可变量 immutable
Solidity immutable 是另一种常量的表达方式。与常量类似,但是不必硬编码,可以在构造函数时传值,部署后无法改变。
immutable 不可变量同样不会占用状态变量存储空间,在部署时,变量的值会被追加的运行时字节码中, 因此它比使用状态变量便宜的多,也同样带来了更多的安全性。
1 | address public immutable owner = msg.sender; |
Solidity 合约继承
virtual 和 override
solidity 引入了 virtual,override 关键字,用于重写函数。
父合约可以使用 virtual 关键字声明一个虚函数,子合约使用 override 关键字来覆盖父合约的方法
1 | // SPDX-License-Identifier: MIT |
abstract
1 | // SPDX-License-Identifier: MIT |
Solidity 异常处理
Solidity 是通过回退状态的方式来处理异常错误。
Solidity 发生异常时,会撤消当前调用和所有子调用改变的状态,同时给调用者返回一个错误标识。
Solidity 提供了require 、assert 和 revert 来处理异常。
require
1 | uint a = 8; |
随便输入一个不等于8的数字提示
assert
1 | function shuru2(uint b) public view returns (uint) { |
随便输入一个不等于8的数字提示
require、assert 使用场景
require() 函数用于检测输入变量或状态变量是否满足条件,以及验证调用外部合约的返回值。
require() 语句的失败报错,应该被看作一个正常的判断语句流程不能通过的事件。
assert()语句的失败报错,意味着发生了代码层面的错误事件,很大可能是合约中有一个bug需要修复。
delete
用于将某个变量重置为初始值。对于整数,运算符的效果等同于a = 0。而对于定长数组,则是把数组中的每个元素置为初始值,变长数组则是将长度置为0。对于结构体,也是类似,是将所有的成员均重置为初始值。
1 | uint data; |
接受函数receive
1 | // 定义事件 |
回退函数
1 | event fallbackCalled(address Sender, uint Value, bytes Data); |
回退函数fallback和receive区别
简单来说,合约接收ETH时,msg.data为空且存在receive()时,会触发receive();msg.data不为空或不存在receive()时,会触发fallback(),此时fallback()必须为payable。
receive()和payable fallback()均不存在的时候,向合约直接发送ETH将会报错(你仍可以通过带有payable的函数向合约发送ETH)。
1 | 触发fallback() 还是 receive()? |
特点
- 一个合约最多存在一个回退函数。
- 它必须被标记为外部(external)函数。
selfdestruct 自毁函数
msg.sender和tx.origin的区别
在Solidity中,
msg.sender和tx.origin都代表了交易的发送者,但两者的含义和应用场景有所不同。
msg.sender:它代表直接调用智能合约函数的账户地址或智能合约地址。无论是外部账户还是智能合约内部的其他合约,只要是直接发起调用的,其地址都会被记录为msg.sender。这意味着,如果一个合约A内部调用了另一个合约B的一个函数,那么在合约B中,msg.sender将表示合约A的地址。tx.origin:它代表整个交易过程中最初的那个交易发送方的地址。这通常是一个外部账户的地址,因为只有外部账户的地址才被视为交易的发起者。在智能合约内部,如果一个合约接收到来自外部账户的交易调用,那么在合约内部,tx.origin将表示发起该交易的外部账户地址。
简而言之,
msg.sender关注的是直接调用者,而tx.origin关注的是原始交易的发送者。在实际应用中,开发者需要根据具体的场景和需求来决定使用哪一个。
abi编码
1 | // SPDX-License-Identifier: UNLICENSED |


abi.encodePacked(x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 进行打包编码。在 Solidity 中,当需要将多个类型不同的参数一起传递给一个函数时,可以使用 abi.encodePacked() 函数将这些参数打包成一个字节数组。这样可以减少调用数据的成本,因为打包后的数据只需要占用一个存储空间。
abi.encodeWithSignature() 函数用于将参数编码为字节数组,并附加一个签名。这个签名可以用于在智能合约中调用该函数时进行验证。
具体来说,abi.encodeWithSignature(“core(uint256,address,string,uint256[2])”, x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 按照指定的函数签名 “core(uint256,address,string,uint256[2])” 进行编码,生成一个字节数组。这个字节数组可以作为交易数据或消息体发送给其他智能合约。
需要注意的是,使用 abi.encodeWithSignature() 函数时,需要确保传入的参数类型与函数签名中的参数类型相匹配,否则会导致编码失败。
abi.encodeWithSelector() 函数用于将参数编码为字节数组,并附加一个选择器。这个选择器可以用于在智能合约中调用该函数时进行验证。
具体来说,abi.encodeWithSelector(bytes4(keccak256(“core(uint256,address,string,uint256[2])”)), x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 按照指定的函数签名 “core(uint256,address,string,uint256[2])” 进行编码,生成一个字节数组。这个字节数组可以作为交易数据或消息体发送给其他智能合约。
需要注意的是,使用 abi.encodeWithSelector() 函数时,需要确保传入的参数类型与函数签名中的参数类型相匹配,否则会导致编码失败。
完结