1. 变量
在Solidity中,存在三种主要类型的变量:局部(Local)变量、状态(State)变量和全局(Global)变量。它们的作用范围和行为各不相同。需要注意的一点是,状态变量和全局变量的使用可能会耗费更多的gas,因为它们涉及到在区块链上存储和读取数据。因此,应该尽量减少这两种类型变量的使用,特别是在需要大量计算的函数中。
1.1 局部变量(Local Variables)
局部变量是在函数内部声明的变量。它们只能在声明它们的函数中访问,当函数执行结束后,它们就会被销毁。例如:
function doSomething() public {
uint localVariable = 10; // 这是个局部变量
}
这里,localVariable
只在doSomething
函数中存在和可访问。
1.2 状态变量(State Variables)
状态变量是在合约级别声明的变量。它们的生命周期与合约相同,并且在整个合约中都是可访问的。状态变量存储在区块链的存储中,这意味着它们的状态在事务之间也会持久化。例如:
contract MyContract {
uint stateVariable; // 这是个状态变量
function doSomething() public {
stateVariable = 10;
}
}
这里,stateVariable
在MyContract
的所有函数中都可以访问。
1.3 全局变量(Global Variables)
全局变量在所有合约中都是可访问的,并且它们通常用于获取有关区块链本身或特定交易的信息。虽然它们被称为”全局”变量,但实际上它们是一组预定义的变量,不能被更改,只能用于读取。例如:
function showInfo() public view returns (address, uint) {
return (msg.sender, now);
}
这里,msg.sender
和now
是全局变量,分别代表当前函数调用的发送者地址和当前块的时间戳。
在Solidity中,全局变量是包含关于区块链、交易或合约本身的关键信息的一组预定义的变量。它们包括:
- block:这个全局变量包含了当前区块的信息如下:
block.number
(当前区块的编号)block.timestamp
(当前区块的时间戳)block.difficulty
(当前区块的挖矿困难度)block.gaslimit
(当前区块的gas上限)
- msg:此变量包含了当前交易的信息,如:
msg.sender
(当前调用者的地址)msg.value
(在交易中发送的以太币数量,以wei为单位)msg.data
(完整的调用数据)msg.sig
(调用的函数签名)msg.gas
(在发送交易时提供的gas)
- tx:此变量在函数执行过程中包含了当前交易的信息,如:
tx.origin
(执行当前调用的外部账户的地址,不是合约地址)
- now:当前区块的时间戳,相当于
block.timestamp
。 - abi:这是一个关于当前合约ABI编码和解码函数的全局对象,包括:
abi.encode(...)
abi.encodePacked(...)
abi.encodeWithSelector(...)
abi.encodeWithSignature(...)
abi.decode(...)
- this:此变量指向当前合约,可用以调用合约自身的函数及合约地址。
- gasleft():此函数返回当前函数还可使用的gas量。
以上就是Solidity支持的主要全局变量和函数。需要注意的是,因为这些全局变量和函数提供了关于区块链和交易的信息,所以它们只在函数执行期间有效。之后的代码执行可能会看到全新的值。
1.4 示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract Variables {
// 状态变量存储在链上
string public hi = "hello";
uint256 public i = 234;
function doSomething() public view {
// 局部变量,定义在函数中,不在链上存储
uint256 localVariable = 10;
// 通过全局变量msg获取合约调用者地址
address caller = msg.sender;
// 通过全局变量block获取当前区块链高度
uint bn = block.number;
}
}
2. 常量
在Solidity中,有两种主要的方式可以声明不变的(不可修改的)值:常量Constants和Immutable。
2.1 常量Constants
constant
关键字表示变量的值在编译时就被确定,且在整个合约生命周期中不会改变。它们不会占用存储空间,也不能与状态变量互动。constant
通常用于定义固定的值,如数学常数、固定地址等。例如:
uint constant X = 32;
string constant TEXT = "Hello, World!";
在这里,X
和TEXT
在整个合约生命周期中都是不变的。
2.2 Immutable(不可变)
immutable
是个较新的关键字。这种类型的变量在创建合约时可以被赋值一次,且此后其值在合约生命周期内不可更改。不同于constant
,immutable
变量的值可以在构造函数中进行计算并在运行时赋值。它们保存在合约的代码中,不占用存储空间。例如:
address immutable owner;
constructor() {
owner = msg.sender;
}
在这个例子中,owner
只在构造函数中被赋值,然后在合约生命周期内保持不变。
值得注意的是,尽管immutable
和constant
都是用来生成不可变的变量,但它们适用于不同的场景。如果你的值在编译时已知并且永远不会改变,应使用constant
。如果你的值需要在运行时(例如在构造函数中)计算或稍后确定,应使用immutable
。
2.3 示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract Constants{
address immutable public owner;
uint constant public num = 1234;
constructor(){
owner = msg.sender;
}
function setOwner(address _addr)public {
owner = _addr; // TypeError: Cannot write to immutable here: Immutable variables can only be initialized inline or assigned directly in the constructor.
}
function setNum(uint _num)public {
num = _num; // TypeError: Cannot assign to a constant variable.
}
}
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特