Solidity v0.7.0 重大变更

本节重点介绍了 Solidity 版本 0.7.0 中引入的主要重大变更,以及变更背后的原因和如何变更日志受影响的代码。 完整列表请查看 变更日志.

语义的静默变化

  • 通过非字面量对字面量进行指数运算和位移(例如 1 << x2 ** x)将始终使用类型 uint256 (对于非负字面量)或 int256 (对于负字面量)来执行操作。 之前,操作是在移位量/指数的类型中执行的,这可能会导致误解。

语法的变化

  • 在外部函数和合约创建调用中,Ether 和 gas 现在使用新语法指定:x.f{gas: 10000, value: 2 ether}(arg1, arg2)。 旧语法 – x.f.gas(10000).value(2 ether)(arg1, arg2) – 将导致错误。

  • 全局变量 now 已被弃用,应该使用 block.timestamp。 单一标识符 now 对于全局变量来说过于通用,可能会给人一种在交易处理过程中会变化的印象,而 block.timestamp 正确地反映了它只是区块的一个属性。

  • NatSpec 注释仅允许用于公共状态变量,而不适用于本地或内部变量。

  • 令牌 gwei 现在是一个关键字(用于指定,例如 2 gwei 作为一个数字)并且不能用作标识符。

  • 字符串字面量现在只能包含可打印的 ASCII 字符,这也包括多种转义序列,例如十六进制(\xff)和 Unicode 转义(\u20ac)。

  • 现在支持 Unicode 字符串字面量,以适应有效的 UTF-8 序列。它们以 unicode 前缀标识:unicode"Hello 😃".

  • 状态可变性:函数的状态可变性现在可以在继承期间受到限制: 默认状态可变性的函数可以被 pureview 函数重写,而 view 函数可以被 pure 函数重写。 同时,公共状态变量被视为 view,如果它们是常量,则甚至是 pure

内联汇编

  • 不允许在内联汇编中使用用户定义的函数和变量名称中的 .。 如果你在仅 Yul 模式下使用 Solidity,则仍然有效。

  • 存储指针变量 x 的槽和偏移量通过 x.slotx.offset 访问,而不是 x_slotx_offset

移除未使用或不安全的特性

存储外的映射

  • 如果结构或数组包含映射,则只能在存储中使用。 之前,映射成员在内存中被静默跳过,这令人困惑且容易出错。

  • 如果存储中的结构或数组包含映射,则赋值无效。 之前,映射在复制操作中被静默跳过,这令人误解且容易出错。

函数和事件

  • 构造函数不再需要可见性(public / internal):为了防止合约被创建,可以将其标记为 abstract。 这使得构造函数的可见性概念变得过时。

  • 类型检查器:不允许库函数使用 virtual: 由于库不能被继承,库函数不应为虚拟的。

  • 不允许在同一继承层次结构中有多个同名且参数类型相同的事件。

  • using A for B 仅影响提到的合约。 之前,效果是继承的。现在,你必须在所有使用该特性的派生合约中重复 using 语句。

表达式

  • 不允许对有符号类型进行位移。 之前,允许对负数进行位移,但在运行时会回退。

  • 移除了 finneyszabo 面额。 它们很少使用,并且无法清晰地显示实际金额。相反,可以使用显式值,如 1e20 或非常常见的 gwei

声明

  • 关键字 var 不再可用。 之前,这个关键字会解析但导致类型错误,并提供关于使用哪种类型的建议。现在,它会导致解析器错误。

接口变化

  • JSON AST:用 kind: "hexString" 标记十六进制字符串字面量。

  • JSON AST:值为 null 的成员从 JSON 输出中移除。

  • NatSpec:构造函数和函数具有一致的用户文档输出。

如何变更日志你的代码

本节提供了有关如何变更日志先前代码以应对每个重大变更的详细说明。

  • x.f.value(...)() 更改为 x.f{value: ...}()。类似地,将 (new C).value(...)() 更改为 new C{value: ...}(),将 x.f.gas(...).value(...)() 更改为 x.f{gas: ..., value: ...}()

  • now 更改为 block.timestamp

  • 将移位运算符右操作数的类型更改为无符号类型。例如,将 x >> (256 - y) 更改为 x >> uint(256 - y)

  • 如有需要,在所有派生合约中重复 using A for B 语句。

  • 从每个构造函数中移除 public 关键字。

  • 从每个构造函数中移除 internal 关键字,并将 abstract 添加到合约中(如果尚未存在)。

  • 将内联汇编中的 _slot_offset 后缀更改为 .slot.offset