******************************** Solidity v0.7.0 重大变更 ******************************** 本节重点介绍了 Solidity 版本 0.7.0 中引入的主要重大变更,以及变更背后的原因和如何变更日志受影响的代码。 完整列表请查看 `变更日志 `_. 语义的静默变化 =============================== * 通过非字面量对字面量进行指数运算和位移(例如 ``1 << x`` 或 ``2 ** 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 😃"``. * 状态可变性:函数的状态可变性现在可以在继承期间受到限制: 默认状态可变性的函数可以被 ``pure`` 和 ``view`` 函数重写,而 ``view`` 函数可以被 ``pure`` 函数重写。 同时,公共状态变量被视为 ``view``,如果它们是常量,则甚至是 ``pure``。 内联汇编 --------------- * 不允许在内联汇编中使用用户定义的函数和变量名称中的 ``.``。 如果你在仅 Yul 模式下使用 Solidity,则仍然有效。 * 存储指针变量 ``x`` 的槽和偏移量通过 ``x.slot`` 和 ``x.offset`` 访问,而不是 ``x_slot`` 和 ``x_offset``。 移除未使用或不安全的特性 ==================================== 存储外的映射 ------------------------ * 如果结构或数组包含映射,则只能在存储中使用。 之前,映射成员在内存中被静默跳过,这令人困惑且容易出错。 * 如果存储中的结构或数组包含映射,则赋值无效。 之前,映射在复制操作中被静默跳过,这令人误解且容易出错。 函数和事件 -------------------- * 构造函数不再需要可见性(``public`` / ``internal``):为了防止合约被创建,可以将其标记为 ``abstract``。 这使得构造函数的可见性概念变得过时。 * 类型检查器:不允许库函数使用 ``virtual``: 由于库不能被继承,库函数不应为虚拟的。 * 不允许在同一继承层次结构中有多个同名且参数类型相同的事件。 * ``using A for B`` 仅影响提到的合约。 之前,效果是继承的。现在,你必须在所有使用该特性的派生合约中重复 ``using`` 语句。 表达式 ----------- * 不允许对有符号类型进行位移。 之前,允许对负数进行位移,但在运行时会回退。 * 移除了 ``finney`` 和 ``szabo`` 面额。 它们很少使用,并且无法清晰地显示实际金额。相反,可以使用显式值,如 ``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``。