1

错误检查

  • throw: 抛出异常。已被废弃。
  • revert(): 抛出异常,并回滚到调用前的状态。
  • require(bool): require(false) 抛出异常,并回滚到调用前的状态,并返回剩余的 gas。用于检查有效条件,比如检查函数输入和返回、检查调用者(require(msg.sender == owner))。
  • assert(bool): 。assert(false) 抛出异常,并回滚到调用前的状态,并消耗掉所有的 gas。用于检查内部错误(internal errors),比如上溢和下溢。可以利用消耗掉所有的 gas的特性,防止或者惩罚恶意攻击。
if(true){
    // 抛出异常,不往下走
    throw;
}

if(true){
    // 抛出异常,不往下走
    revert();
}

// 抛出异常,不往下走
require(false);

// 抛出异常,不往下走
assert(false);

数组

数组(Arrays):相同类型的元素的集合所组成的数据结构。

数组类型:

  • 固定长度数组。 uint[5] dynamicArr
  • 动态长度数组。 uint[] fixedArr

成员:

  • length 。 固定长度数组为声明时的长度,动态长度数组为数组中含有多少元素。
  • push 。往动态长度数组中增加一个元素,固定长度数组没有该方法。
// 声明
uint[] dynamicArr;
uint[3] fixedArr;

// 创建数组
uint[] dynamicArr = new uint[](7); // 赋值长度为 7 的动态长度数组
uint[3] fixedArr = new uint[3](); // 报错
uint[3] fixedArr = [1, 2, 3]; // 赋值长度为 3 的固定长度数组


// 成员赋值
dynamicArr[0] = 1; 
fixedArr[0] = 1; 
fixedArr[3] = 1; // 报错

// push 新元素
dynamicArr.push(1); // 正确
fixedArr.push(1); // 报错。fixedArr 没有 push 属性。

// 访问元素
dynamicArr[1]; // 0
fixedArr[1]; // 2

// 获取数组长度
dynamicArr.length; // push 新元素后,长度为 7+1。
fixedArr.length // 3


// 改变数组长度
dynamicArr.length = dynamicArr.length - 1; // 正确
fixedArr.length = fixedArr.length - 1; // 报错。不能改变固定长度数组的长度


// 遍历数组
for(uint i; i < dynamicArr.length; i++){}
for(uint i; i < fixedArr.length; i++){}
// 固定长度数组转换为动态长度数组。由于语言完善的问题,支持状态变量之间的转换,未来可能会取消该限制。
uint[] x = [1, 3, 4]; // 正确。
uint[] memory x = [1, 3, 4]; // 报错。固定长度 memory 的数组,不能转换为动态长度 memory 的数组。

结构体

结构体(Structs): 结构体是一些元素的集合。合法元素类型包括:值类型、数组和映射等,包括:结构体。

// 声明
struc Employee{ // 大写 E
    address id;
    uint salary;
    uint lastPayDay;
}

// 创建结构体
Employee employee = Employee(0x1, 0, 0);


// 访问成员
employee.id

数据存储

  • storage 持久性
  • memory 临时空间
  • calldata 类似 memory,执行完后被抹除

相同存储空间赋值

  • 传递引用 reference(EVM 上的内存地址)。 storage = storage

不同存储空间变量赋值

  • 拷贝
    memory a = storage ,b 在 memory 内存中重新开辟一个空间给 employee 类型,并且将 employee 这个值拷贝到 memory 内存空间中。将 memory 内存地址赋值给 memory 变量。所以 memory 变量内存地址并不是指向 storage 内存地址,而是一个 memory 变量的全新的地址。同样的将 memory 赋值给 storage 变量,也会进行一个拷贝。注意,只能将 memory 变量赋值给状态变量,而不是本地 storage 变量。因为我们只能在状态变量中分配内存空间。

delete

delete 初始化变量、删除数组中的内容

http://www.tryblockchain.org/...

@黄敏之-助教; EVM的定义就是0值等同于回收,把一个storage设为0是消耗负值的gas

clipboard.png

实验结果: remove约等于remove2,同时远远小于remove3和4。且执行完remove12后下次remove34的gas消耗大大增加。这个很有意思。1和2做的都是释放内存的操作,所以有负gas的福利;释放内存后如果要再赋值,需要重新申请内存,所以这样会消耗更多的gas。

delete owner 
delete arr 初始化arr length =0
delete arr[i] 初始化 arr 的某个元素,但此时 arr[i]  还占据空间,length 也没有变。

// 因此需要以下两步,真正的删除元素
arr[i] = arr[arr.length - 1]
arr.lenght -= 1;

未完成,待更新...


fitfish
1.6k 声望950 粉丝

前端第七年,写一个 RN 专栏。