第一章 数组

数组

如果你想建立一个集合,可以使用数组这种数据类型。Solidity支持两种数组: 静态数组和动态数组

// 固定长度为3的静态数组: 
uint[3] fixedArray; 
// 固定长度为5的string类型的静态数组: 
string[6] stringArray; 
// 动态数组,长度不固定,可以动态添加元素: 
uint[] dynamicArray; 

你也可以建立一个结构体类型的数组,例如上一章提到的Book:

// 这是动态数组,我们可以不断添加元素 
Book[] books; 

记住:状态变量被永久保存在区块链中。所以在你的合约中创建动态数组来保存结构化的数据是非常有意义的。

公共数组

你可以定义公共数组,使用 public 关键字。Solidity 会为公共数组自动创建 getter 方法.。

定义公共数组的语法如下:

Book[] public books; 

其它的合约可以从这个数组读取数据(但不能写入数据),所以这是一种在合约中保存公共数据的方法。

实战

为了把小蚂蚁保存在我们的合约里,并且能够让其它合约看到这些蚂蚁,我们需要一个公共数组。

  1. 创建一个数据类型为 Ant 的结构体数组,用 public 修饰,命名为:ants
pragma solidity ^0.4.20;

contract AntFamily {
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
  }
  
  Ant[] public ants;
  
  function createAnt(string _name, uint _dna) {
    
  }
  
}

第二章 使用结构体和数组

创建新的结构体

还记得上个例子中的 Book 结构体吗?

struct Book {
    string name;
    uint page;
}

Book[] public books;

现在我们学习创建新的 Book 结构体,然后把它加入到名为 book 的数组中。

// 创建一个新的Book: 
Book fish = Book("fish", 156); 
// 将新创建的fish添加进book数组: 
books.push(fish); 

你也可以将上面的两步合并成一步,用一行代码实现更简洁:

books.push(Book("fish", 156)); 

注:array.push() 是在数组的尾部加入新元素 ,所以元素在数组中的顺序就是我们添加的顺序, 如:

uint[] numbers; 
numbers.push(1); 
numbers.push(2); 
numbers.push(3); 
// 这时候numbers数组是 [1, 2, 3]
实战

让我们创建名为createAnt的函数来做点儿什么吧。

  1. 在函数体里新创建一个 Ant, 然后把它加入 ants 数组中。 新创建蚂蚁的 name 和 dna,来自于函数的参数。
  2. 让我们用一行代码简洁地完成它。
pragma solidity ^0.4.20;

contract AntFamily {
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
  }
  
  Ant[] public ants;
  
  function createAnt(string _name, uint _dna) {
    ants.push(Ant(_name, _dna));
  }
  
}

第三章 keccak256散列函数使用

散列函数keccak256是把一个字符串转换为一个256位的16进制数字。字符串的一个微小变化会引起散列数据的极大变化。在我们的课程中,我们利用它来造一个伪随机数。

下面是一个例子:

//bc6bb462e38af7da48e0ae7b5cbae860141c04e5af2cf92328cd6548df111fcb
keccak256("xxx");
//3a60bbc72c8477330650d5aae5e7d73f0d15a6efe7e8aab4fa3c33a3a8c3b467
keccak256("xxy");

如上所示,输入的字符串只改变了一个字母,输出就已经天壤之别了。

注: 在区块链中安全地产生一个随机数是一个很难的问题,本课程的方法不安全,但是在我们的蚂蚁DNA算法里不是那么重要,这已经很好地满足我们的需求了。

实战

建立一个函数,命名为createRandomAnt。它将被传入一个变量 _name (数据类型是 string)。

  1. 函数的第一行代码取 _name 的 keccak256 散列值生成一个伪随机十六进制数,类型转换为 uint, 最后保存在类型为 uint 名为 rand 的变量中。
  2. 我们只想让我们的DNA的长度为12位。所以第二行代码应该 计算 上面计算的数值对 dnaModulus 求余数(%),结果保存在一个类型为 uint 的变量里,命名为 randDna。
  3. 第三行调用 createAnt 函数, 传入参数: _name 和 randDna。
  4. 整个函数应该是5行代码 (包括函数的结束符号 } )。
pragma solidity ^0.4.20;

contract AntFamily {
  
  // 在这里建立事件
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
  }
  
  Ant[] public ants;
  
  function createAnt(string _name, uint _dna) {
    ants.push(Ant(_name, _dna));
  }
  
  function createRandomAnt(string _name) {
    uint rand = uint(keccak256(_name));
	  uint randDna = rand % dnaModulus;
    createAnt(_name, randDna);
  }
  
}

第四章 事件

事件是合约和区块链通讯的一种机制。你的应用可以“监听”某些事件,并做出反应。我们使用event关键字来定义事件,使用emit关键字在函数中触发事件。

实战

我们想每当一个蚂蚁创造出来时,我们的应用都能监听到这个事件,并将它显示出来。

  1. 定义一个事件叫做NewAnt。

    它有3个参数: antId (uint) 带indexed属性, name (string), 和 dna (uint)。

  2. 修改 createAnt 函数使得当新蚂蚁造出来并加入ants数组后,生成事件NewAnt。

  3. 需要定义蚂蚁id。 array.push() 返回数组的长度类型是uint,因为数组的第一个元素的索引是 0, 所以array.push() - 1 将是我们加入的蚂蚁的索引。 ants.push() - 1 就是 id,数据类型是 uint。在下一行中你可以把它用到 NewAnt 事件中。

pragma solidity ^0.4.20;

contract AntFamily {
  
  event NewAnt(uint indexed antId, string name, uint dna);
  
  uint dnaDigits = 12;
  uint dnaModulus = 10 ** dnaDigits;
  
  struct Ant {
    string name;
    uint dna;
  }
  
  Ant[] public ants;
  
  function createAnt(string _name, uint _dna) {
    uint id = ants.push(Ant(_name, _dna)) - 1;
    emit NewAnt(id, _name, _dna);
  }
  
  function createRandomAnt(string _name) {
    uint rand = uint(keccak256(_name));
    uint randDna = rand % dnaModulus;
    createAnt(_name, randDna);
  }
  
}
Logo

为所有Web3兴趣爱好者提供学习成长、分享交流、生态实践、资源工具等服务,作为Anome Land原住民可不断优先享受各种福利,共同打造全球最大的Web3 UGC游戏平台。

更多推荐