Solidity中有个特殊的操作符delete用于释放空间,因为区块链技术做为一种公用资源,为避免大家滥用。且鼓励主动对空间的回收,释放空间将会返还一些gas。

  delete关键字的作用是对某个类型值a赋予初始值。比如如果删除整数delete a等同于a = 0

一.删除基本类型
  对于区块链技术删除基本类型,使用delete会设置为对应的初始值:

  删除bool类型是false,变长字节数组是0x0。string则是空串。

1.删除枚举
  删除枚举类型时,会将其值重置为序号为0的值。

pragma solidity ^0.4.0;

contract DeleteEnum {

    enum Light{RED, GREEN, YELLOW}

    Light light;

    function f() returns(Light) {
light = Light.GREEN;
delete light;
return light;
}
}

  上面的例子中,删除light后,light将被置为序号为0的值。

2.删除函数
  尝试了一下删除函数,会报错Error: Expression has to be an lvalue.,看来我们不能删除函数。

二.删除复杂类型

1.删除结构体
  删除一个结构体,会将区块链技术其中的所有成员变量一一置为初值,我们来看一个例子。

pragma solidity ^0.4.0;

contract Deletetruct {

    struct S{
uint a;
string b;
bytes c;
} S s; function delStruct() returns(uint, string, bytes) {
s = S(10, "Hello world!", "abc");
//删除结构体将重置所有元素
delete s;
return (s.a, s.b, s.c);
}
}

  在上面的例子中,我们声明了结构体s,调用delete s,结构体的值将变为其对应类型uint,string,bytes的初始值0,空串和0x0。

2.删除映射
  映射是一个特殊的存在,由于映射的键并不总是能有效遍历(数据结构没有提供接口,也并不总是需要关心所有键是什么),所存的键的数量往往是非常大的,所以我们并不能直接删除一个区块链技术的映射。
        //Unary operator delete cannot be applied to type mapping(address => uint256) //delete map;
  如果直接删除一个映射会报错Unary operator delete cannot be applied
  但我们可以指定键来删除映射中的某一项:

map[msg.sender] = 100; //可以按key删除映射
delete map[msg.sender];

3.删除结构体中的映射 

  如果删除一个结构体时,其中含有映射类型,会跳过映射类型。我们来看一个删除含映射的结构体示例:

pragma solidity ^0.4.0;

contract MappingStructDelete {

    struct MapStruct{
mapping(address => uint) m;
uint i;
} MapStruct ms; function delMapping() returns(uint, uint) {
ms = MapStruct(200);
ms.m[msg.sender] = 2000; //删除一个结构体
delete ms; return (ms.m[msg.sender], ms.i);
}
}

  上面的示例中,删除结构体ms,并没有影响其中映射ms.m的值。

三.删除数组
  对于定长数组,删除时,是将数组内所有元素置为初值。

bytes32 by = "123";
//0x0000000000000000000000000000000000000000000000000000000000000000

  而对于变长数组时,则是将长度置为0。

pragma solidity ^0.4.0;

contract DeleteDynamicArray {

    function delDynamicArr() returns(uint) {
uint[] memory a = new uint[](7);
a[0] = 100;
a[1] = 200; delete a; return (a.length);
}
}

  上述的代码a.length将返回长度为0。
2.删除数组的一个元素
  我们也可以删除数组的一个元素,有一点违反直觉的是,删除一个元素后,数组会留个空隙在那里。比如三个元素的数组,删除了第二个元素,只是将第二个元素置为了初始值,其它没变。

pragma solidity ^0.4.0;

contract DeleteArrayEle {

    function delArrEle() returns(uint, uint, uint) {
uint[] memory arr = new uint[](3); arr[0] = 1;
arr[1] = 2;
arr[2] = 3; delete arr[1]; return (arr[0], arr[1], arr[2]);
}
}

  上述的代码运行后,将返回1,0,3。删除只是赋值,并没有移动元素。

四.gas使用的考虑
  上文中,我们了解到,删除时会忽略映射,以及数组的某个元素被删除后,并不会自动整理数组。这些看起来很不符合常理,其实是基于对gas限制的考虑。因为如果映射或数组非常大的情况下,删除或维护它们将变得非常消耗gas。

  不过,清理空间,可以获得gas的返还。但无特别意义的数组的整理和删除,只会消耗更多gas,需要在业务实现上进行权衡。

清理的最佳实践
  由于本身并未提供对映射这样的大对象的清理,所以存储并遍历它们来进行清理,显得特别消耗gas。一种实践就是能复用就复用,一般不主动清理。下面是一个数组的插入实现,比如增加一个计数器,直接忽略已使用过的位置。

  上面的例子中,我们在区块链技术数组新增时,直接忽略掉已使用过的槽位。而在代码内,我们使用numElements来代替array.length,以获取当前数组所在的位置。

  如果这种大对象是在某个事件发生时,一次性使用,然后需要回收的。一个更有效的方式是,在发生某个事件时,创建一个新合约,在新合约完成逻辑,完成后,让合约suicide。清理合约占用空间返还的gas就退还给了调用者,来节省主动遍历删除消耗的额外gas。

五.删除的注意事项
  区块链技术删除本质是对一个变量赋初值。所以我们删除storage的引用时会报错,因为storage的引用并没有自己已分配的存储空间,所以不能对storage的引用直接赋初值。

pragma solidity ^0.4.0;

contract DeleteStorageRef {

    struct S{}

    S s;

    function DelStorageRef() {
S storageRef = s; //Error: Unary operator delete cannot be applied to type struct DeleteStorageRef.S storage
//delete storageRef; delete s;
}
}

  上面的例子中,删除storageRef会报错。

文章来源:https://blog.csdn.net/qq_33764491/article/details/81386374

Solidity的delete操作的更多相关文章

  1. solidity的delete操作汇总

    简介 Solidity中的特殊操作符delete用于释放空间,为鼓励主动对空间的回收,释放空间将会返还一些gas. delete操作符可以用于任何变量,将其设置成默认值0. 删除枚举类型时,会将其值重 ...

  2. 关于JavaScript中的delete操作

    关于JavaScript中的delete操作 看到一道题,是这样的: (function(x){ delete x; return x; })(1); 1 null undefined Error 我 ...

  3. 表上的DELETE操作

    在今天的文章里,我想给你快速展示下当我们从表里删除记录时,在SQL Server里发生了什么.首先我们来创建一个简单的表,在8KB的页上刚好能插入4条记录. -- Create a simple ta ...

  4. mysql没有delete操作,那是delete from操作,

    1.mysql没有delete操作,那是delete from操作, 2.DELETE FROM table_name [WHERE Clause]

  5. SVN中正确的add操作和delete操作

    add操作: delete操作:

  6. 一起学HBase——总结HBase中的PUT、GET、DELETE操作

    传统的关系型数据库有CRUD增删改查操作,同样对于NoSQL列式数据库也有CRUD操作.本文对HBase中常用的Scan.GET.PUT.DELETE操作的用法做个总结. Put操作 Put相当于传统 ...

  7. RMAN命令DELETE操作总结

    本篇总结一下RMAN命令中的DELETE操作,DELETE命令用于删除RMAN备份记录以及相应的物理文件. To delete physical backups and copies as well ...

  8. Mybatis之执行insert、update和delete操作时自动提交

    单独使用Mybaits,而没有集成Spring的话,执行insert.update和delete操作是不会自动提交的,即执行语句后不会在数据库有对应的数据变化. 解决这样的方法就是打开自动提交开关,在 ...

  9. 【mybatis】service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据【事务的问题】

    问题描述: service层中一个方法中使用mybatis进行数据库的 多个修改操作,可能是update也可能是delete操作,但是sql语句命名执行并且在控制台打印出来了,但是数据库中未更新到数据 ...

随机推荐

  1. 软件工程课堂练习&课下作业

    题目:返回一个整数数组中最大子数组的和.一.设计思路按顺序定义子数组的和,如果为负,则选下一位数为子数组的和,反之则两个相加为子数组的和.二.源代码 package test;import java. ...

  2. POJ2270&&Hdu1808 Halloween treats 2017-06-29 14:29 40人阅读 评论(0) 收藏

    Halloween treats Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8565   Accepted: 3111 ...

  3. 《mysql必知必会》学习_第9章_20180731_欢

    第九章,用正则表达式进行搜索. P52 select prod_name from products where prod_name regexp '1000' order by prod_name; ...

  4. 通过端口号查找进程号并杀掉进程window和Linux版本

    window版本: cmd下执行: 1.查找某端口号下的进程: netstat -ano|findstr 8080 如果该端口号存在进程,执行完命令后会出现列表,最后一列的数字表示该端口号下的进程号 ...

  5. 利用Delphi编程控制摄像头(图)

    你的电脑有没有摄像头?看到别人用QQ玩视屏你会不会去想怎么实现的?这里介绍使用DELPHI使用MS的 AVICAP32.DLL就可轻松的实现对摄像头编程,如果再加上你的网络编程水平,实现一个视屏聊天就 ...

  6. OmniThreadLibrary学习笔记

    http://blog.sina.com.cn/s/articlelist_1157240623_6_1.html 非常好的控件,仔细看

  7. Android-Retrofit-2.0-Post与Get-请求有道词典翻译

    Retrofit-2.0版本后,内置已经集成了OKHttp,在使用Retrofit的时候 看似是Retrofit去网络请求的 实际上Retrofit只是封装,所以不要以为Retrofit是网络请求框架 ...

  8. GDI+配置

    GDI+的配置过程: 一.打开stdafx.h文件,在其中加入: #include "Gdiplus.h" #pragma comment(lib,"Gdiplus.h& ...

  9. 如何在C#中引入CPLEX的dll(CPLEX系列-教程一)

    以前写在CSDN上的文章.转到博客园之后,打算把这个教程移过来,顺便完善后面的教程.主要是在Asp.Net+EF6里面使用cplex,完成一个最优生产计划的决策.当时在查找如何在C#中引用cplex时 ...

  10. 新建WebAPI项目时遇到的问题

    1   处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler” 以管理员运行下面的命令注册 ...