Solidity v0.6.0重大更新¶
本节重点介绍Solidity 版本0.6.0 中引入的重大突破性变化,以及更改背后的原因以及如何更新受影响的代码。
有关完整列表,请检查 更新日志.
需要明确指定的更改¶
本节列出了现在需要更明确地显示代码的更改, 但是语义不会改变。 对于大多数情况,编译器将提供建议。
- 现在,仅当函数被标记为
virtual
或在接口中定义 时,才可以覆盖。
在接口外部没有实现的函数必须标记为 virtual
。
覆盖函数或修饰符时,必须使用新关键字 override
。 覆盖多个基类定义的函数或修饰符时, 需要像这样 override(Base1, Base2)
列出.
- 访问数组的
length
现在是只读的, 即便是storage 数组. 不能通过修改length来调整数组的大小, 必须通过函数push()
,push(value)
或pop()
或者分配一个完整的数组(不过这会覆盖现有内容)。 这个修改背后的原因是为了防止存储冲突. - 关键字
abstract
用来标记一个抽象合约. 如果合约有没有实现的函数, 需要使用. - 库需要实现所有的函数,不仅仅是内部函数.
- 内联汇编中声明的变量名称可以不再以
_slot
或_offset
结尾。 - 内联汇编中的变量声明可能不会在内联汇编块之外屏蔽声明。
如果名称包含一个点,则该点之前的前缀可能与内联汇编块外部的任何声明都没有冲突。
- 现在不允许状态变量屏蔽。 派生合约只能声明基类合约中都没有同名的可见状态变量
x
(即如果基类合约中有共有的 状态变量x
, 则派生合约不能在声明x
)。
语义和句法变化¶
本节列出了必须修改代码的更改.
- 现在禁止从外部函数类型到
address
的转换。 现在外部函数类型具有一个称为address
的成员属性,类似于现有的selector
成员。 - 对于动态的存储数组, 函数
push(value)
不再返回长度(现在什么都不返回). - 未命名的函数通常称为
fallback function
,已拆分为一个使用fallback
关键字定义的回退函数 和 使用关键字receive
定义的接受以太函数.- 如果有``receive’’函数, 向合约转账的时候会调用,不管是否是调用数据(即便没有以太接收),
receive
函数隐含带有payable
. - 新的回退函数会被调用,当没有其他的函数被匹配时, (如果不存在
receive
函数,则没有调用数据的转账也会调用回退函数). 回退函数可以标记为payable
(也可以不标记). 如果没有payable
那么附加以太的调用会revert.
- 如果有``receive’’函数, 向合约转账的时候会调用,不管是否是调用数据(即便没有以太接收),
如果是需要实现升级或代理模式,则仅需要实现新的回退函数。
新特性¶
本节列出了在Solidity 0.6.0 之前不可能实现的事情,或者在Solidity 0.6.0之前很难实现的事情。
- 加入了 try/catch 语句 使您可以对失败的外部调用做出反应。
struct
和enum
类型可以在文件级别声明.- 数组切片可以用于 calldata 数组, 例如:
abi.decode(msg.data[4:], (uint, uint))
是一个对函数调用payload进行解码底层方法。- Natspec在开发人员文档中支持多个返回参数,并强制执行与
@param
的同名检查。- Yul和Inline Assembly有一个名为
leave
的新语句,该语句退出当前函数.- 现在可以通过
payable(x)
把address
转换为address payable
, 当然x
需要是 地址类型.
接口变化¶
本节列出了与语言本身无关的更改,但这些更改会影响编译器的接口。 如果命令行上使用编译器的, 或编程方式使用, 或分析编译器输出时, 都会产生改变.
新错误报告器¶
A new error reporter was introduced, which aims at producing more accessible error messages on the command line.
It is enabled by default, but passing --old-reporter
falls back to the the deprecated old error reporter.
Metadata 哈希选项¶
The compiler now appends the IPFS hash of the metadata file to the end of the bytecode by default
(for details, see documentation on contract metadata). Before 0.6.0, the compiler appended the
Swarm hash by default, and in order to still support this behaviour,
the new command line option --metadata-hash
was introduced. It allows you to select the hash to be produced and
appended, by passing either ipfs
or swarm
as value to the --metadata-hash
command line option.
Passing the value none
completely removes the hash.
These changes can also be used via the Standard JSON Interface and effect the metadata JSON generated by the compiler.
The recommended way to read the metadata is to read the last two bytes to determine the length of the CBOR encoding and perform a proper decoding on that data block as explained in the metadata section.
Yul 优化器¶
Together with the legacy bytecode optimizer, the Yul optimizer is now enabled by default when you call the compiler
with --optimize
. It can be disabled by calling the compiler with --no-optimize-yul
.
This mostly affects code that uses ABIEncoderV2.
C API Changes¶
The client code that uses the C API of libsolc
is now in control of the memory used by the compiler. To make
this change consistent, solidity_free
was renamed to solidity_reset
, the functions solidity_alloc
and
solidity_free
were added and solidity_compile
now returns a string that must be explicitly freed via
solidity_free()
.
怎样修改代码¶
本节提供有关如何为每个重大变更更新先前代码的详细说明。
- 如果
f
是外部函数类型,address(f)
修改为f.address
- 接收以太的函数,
function () external [payable] { ... }
修改为receive() external payable { ... }
,fallback() external [payable] { ... }
或者两个度加上. 只要有可能,最好是仅仅使用receive
函数. - 修改
uint length = array.push(value)
为array.push(value);
. 通过array.length
获取长度. - 修改
array.length++
为array.push()
去增加storage数组长度, 用pop()
去减少storage数组长度. - 对于函数的
@dev
开发这文档中的每个命名返回参数,请定义一个``@return`` 条目,其中将返回参数名称作为第一个单词。 例如。 已定义函数` f()` 是这样function f() public returns (uint value)
, 记录返回值的文档注释是这样:@return value 这是返回值.
您可以混合使用命名和未命名的返回参数,只要按它们在返回元组类型中出现的顺序排列即可。 - 为内联汇编中的变量声明选择与内联汇编块外的声明不冲突的唯一标识符。
- 为每个非接口函数添加
virtual
. 对于单继承,请在每个重写函数中添加``override``。 对于多重继承,添加override(A, B, ..)
, 在在括号中列出所有覆盖函数的的合约。
当多个基类合约有相同定义的函数时,继承合约必须覆盖所有冲突的函数。