文章目录
- 表达式与控制结构
- 赋值
- 结构化赋值与返回多个值
- 数组和结构体的赋值复杂性
- 作用域和声明
- 检查或不检查的算术运算
- 错误处理:Assert、Require、Revert 和异常
- 通过 assert 进行 Panic 和通过 require 进行 Error
- revert
- try/catch
表达式与控制结构
赋值
结构化赋值与返回多个值
Solidity 内部支持元组类型(tuple types),即由多个可能类型不同、数量在编译时为常数的对象组成的列表。元组可用于一次性返回多个值。这些返回值可以赋值给新声明的变量,也可以赋值给已有变量(或广义上的左值 LValues)。
元组在 Solidity 中并不是一种正式的类型,它们只能用于表达式的语法组合。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;contract C {uint index;function f() public pure returns (uint, bool, uint) {return (7, true, 2);}function g() public {// 用类型声明变量并从返回的元组中赋值,// 不需要指定所有元素(但数量必须一致)。(uint x, , uint y) = f();// 交换变量值的常见技巧 —— 不适用于非值类型的存储变量。(x, y) = (y, x);// 可以省略部分组件(也适用于变量声明)。(index, , ) = f(); // 设置 index 为 7}
}
不允许混合变量声明与非声明赋值,例如以下写法是无效的:(x, uint y) = (1, 2);
注意:当涉及引用类型时(如数组、结构体等),同时对多个变量赋值可能会出现意外的复制行为,需要小心使用。
数组和结构体的赋值复杂性
对于非值类型(如数组和结构体,包括 bytes
和 string
),赋值语义更为复杂。
在下面这个例子中,对 g(x)
的调用对 x
无效,因为它在内存中创建了一个存储值的独立副本。然而,h(x)
可以成功修改 x
,因为它传递的是引用而非副本。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;contract C {uint[20] x;function f() public {g(x);h(x);}function g(uint[20] memory y) internal pure {y[2] = 3;}function h(uint[20] storage y) internal {y[3] = 4;}
}
g(x)
:传入的是memory
类型的副本,对y[2]
的修改不会影响到原始的x
。h(x)
:传入的是storage
引用,对y[3]
的修改将会直接改变合约状态变量x[3]
。
这是 Solidity 中引用类型(如数组、结构体)赋值和传参行为的重要概念,memory 会复制,storage 会引用原始数据。
作用域和声明
声明的变量将具有初始默认值,其字节表示为全零。变量的“默认值”是该类型的典型“零状态”。例如,bool
的默认值是 false
,uint
或 int
类型的默认值是 0
。对于静态大小的数组和 bytes1
到 bytes32
,每个单独的元素将初始化为对应类型的默认值。对于动态大小的数组、bytes
和 string
,默认值是空数组或空字符串。对于 enum
类型,默认值是它的第一个成员。
Solidity 中的作用域遵循 C99(以及许多其他语言)广泛使用的作用域规则:变量从其声明后的立即可见点开始,直到包含声明的最小 { }
块的结束。作为这一规则的例外,for
循环初始化部分声明的变量仅在 for
循环的结束之前可见。
类似参数的变量(函数参数、修饰符参数、catch
参数等)在后续的代码块中可见 —— 对于函数和修饰符参数,它们在函数体和修饰符体内可见;对于 catch
参数,它们在 catch
块内可见。
在代码块外声明的变量和其他项目,例如函数、合约、用户定义的类型等,即使在声明之前,也可以可见。这意味着我们可以在声明之前使用状态变量,并递归调用函数。
因此,以下示例将编译而不会产生警告,因为这两个变量具有相同的名称,但作用域是互不重叠的。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract C {function minimalScoping() pure public {{uint same;same = 1;}{uint same;same = 3;