涉及 LValues 的运算符

如果 a 是一个 LValue(即一个变量或者其它可以被赋值的东西),以下运算符都可以使用简写:

a += e 等同于 a = a + e。 其它运算符 -=*=/=%=|=&= 以及 ^= 都是如此定义的。 a++a-- 分别等同于 a += 1a -= 1,但表达式本身的值等于 a 在计算之前的值。 与之相反,--a++a 虽然最终 a 的结果与之前的表达式相同,但表达式的返回值是计算之后的值。

delete

delete a 的结果是将 a 类型初始值赋值给 a。即对于整型变量来说,相当于 a = 0,delete 也适用于数组,对于动态数组来说,是将重置为数组长度为0的数组,而对于静态数组来说,是将数组中的所有元素重置为初始值。对数组而言,delete a[x] 仅删除数组索引 x 处的元素,其他的元素和长度不变,这以为着数组中留出了一个空位。如果打算删除项,映射可能是更好的选择。

如果对象 a 是结构体,则将结构体中的所有属性(成员)重置。

换句话说,在 delete a 之后 a 的值与在没有赋值的情况下声明 a 的情况相同, 但需要注意以下几点:

delete 对整个映射是无效的(因为映射的键可以是任意的,通常也是未知的)。 因此在你删除一个结构体时,结果将重置所有的非映射属性(成员),这个过程是递归进行的,除非它们是映射。 然而,单个的键及其映射的值是可以被删除的。

理解 delete a 的效果就像是给 a 赋值很重要,换句话说,这相当于在 a 中存储了一个新的对象。

a 是应用变量时,我们可以看到这个区别,delete a 它只会重置 a 本身,而不是更改它之前引用的值。

pragma solidity >=0.4.0 <0.7.0;

contract DeleteLBC {
    uint data;
    uint[] dataArray;

    function f() public {
        uint x = data;
        delete x; // 将 x 设为 0,并不影响数据
        delete data; // 将 data 设为 0,并不影响 x,因为它仍然有个副本
        uint[] storage y = dataArray;
        delete dataArray;
        // 将 dataArray.length 设为 0,但由于 uint[] 是一个复杂的对象,y 也将受到影响,
        // 因为它是一个存储位置是 storage 的对象的别名。
        // 另一方面:"delete y" 是非法的,引用了 storage 对象的局部变量只能由已有的 storage 对象赋值。
        assert(y.length == 0);
    }
}