Solidity学习

# Solidity学习

## Solidity 第一章

pragma solidity ^0.4.19;    //注意分号

comtract XXX {   //需要空格

##### uint 为无符号数据类型,其值不能为负数Solidity中, uint 实际上是 uint256代名词,一个256位的无符号整数。你也可以定义位数少的uints — uint8, uint16, uint32, 等…… 但一般来讲你愿意使用简单的 uint, 除非在某些特殊情况下.

uint dnaDigits = 16;

##### 在solidity中,乘方用**表示,如下

uint dnaModulus = 10 ** dnaDigits;

##### struct结构体,允许你生成一个更复杂的数据类型,它有多个属性;刚刚引进了string。字符串用于保存任意长度的UTF-8编码数据

struct Zombie {

        string name;

        uint dna;

}

##### 构造一个数据类型为Zombie的结构体数组,用public修饰,public数组,Solidity会自动创建getter方法,命名为zombies

Zombie[] public zombies;

##### 建立一个函数 createZombie。 它有两个参数: _name (类型为string), 和 _dna (类型为uint)。注意名字前有下划线

##### 在函数名字后面使用关键字 private 即可。和函数的参数类似,私有函数的名字用(_)起始。

function _createZombie(string _name, uint _dna) private {

        zombies.push(Zombie(_name, _dna));

    }

##### view表示只能读取数据不能更改数据,returns(数据类型)是返回的格式,注意return加s

function _generateRandomDna(string _str) private view returns (uint) {

##### Ethereum 内部有一个散列函数keccak256,它用了SHA3版本。一个散列函数基本上就是把一个字符串转换为一个256位的16进制数字。字符串的一个微小变化会引起散列数据极大变化。

##### 第一行代码取 _str 的 keccak256 散列值生成一个伪随机十六进制数,类型转换为 uint, 最后保存在类型为 uint 名为 rand 的变量中。第二行我们只想让我们的DNA的长度为16位 (还记得 dnaModulus?)。所以第二行代码应该 return 上面计算的数值对 dnaModulus 求余数(%)。

  uint rand = uint(keccak256(_str));

  return rand % dnaModulus;

    }

##### 写一个公共函数,它有一个参数,用来接收僵尸的名字,之后用它生成僵尸的DNA。

function createRandomZombie(string _name) public {

        uint randDna = _generateRandomDna(_name);

        _createZombie(_name, randDna);

    }

}


 

        // 下面是调用合约的方式:

       var abi = /* abi是由编译器生成的 */

var ZombieFactoryContract = web3.eth.contract(abi)

var contractAddress = /* 发布之后在以太坊上生成的合约地址 */

var ZombieFactory = ZombieFactoryContract.at(contractAddress)

// `ZombieFactory` 能访问公共的函数以及事件

// 某个监听文本输入的监听器:

$("#ourButton").click(function(e) {

  var name = $("#nameInput").val()

  //调用合约的 `createRandomZombie` 函数:

  ZombieFactory.createRandomZombie(name)

})

// 监听 `NewZombie` 事件, 并且更新UI

var event = ZombieFactory.NewZombie(function(error, result) {

  if (error) return

  generateZombie(result.zombieId, result.name, result.dna)

})

// 获取 Zombie 的 dna, 更新图像

function generateZombie(id, name, dna) {

  let dnaStr = String(dna)

  // 如果dna少于16位,在它前面用0补上

  while (dnaStr.length < 16)

    dnaStr = "0" + dnaStr

  let zombieDetails = {

    // 前两位数构成头部.我们可能有7种头部, 所以 % 7

    // 得到的数在0-6,再加上1,数的范围变成1-7

    // 通过这样计算:

    headChoice: dnaStr.substring(0, 2) % 7 + 1,

    // 我们得到的图片名称从head1.png 到 head7.png

    // 接下来的两位数构成眼睛, 眼睛变化就对11取模:

    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,

    // 再接下来的两位数构成衣服,衣服变化就对6取模:

    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,

    //最后6位控制颜色. 用css选择器: hue-rotate来更新

    // 360度:

    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),

    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),

    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),

    zombieName: name,

    zombieDescription: "A Level 1 CryptoZombie",

  }

  return zombieDetails

}

## Solidity 第二章

### 映射

 _映射_ 是另一种在 Solidity 中存储有组织数据的方法。

映射是这样定义的:

//对于金融应用程序,将用户的余额保存在一个 uint类型的变量中:

mapping (address => uint) public accountBalance;

//或者可以用来通过userId 存储/查找的用户名

mapping (uint => string) userIdToName;

映射本质上是存储和查找数据所用的键-值对。在第一个例子中,键是一个 address,值是一个 uint,在第二个例子中,键是一个uint,值是一个 string。

### msg.sender

在 Solidity 中,有一些全局变量可以被所有函数调用。 其中一个就是 msg.sender,它指的是当前调用者(或智能合约)的 address。

注意:在 Solidity 中,功能执行始终需要从外部调用者开始。 一个合约只会在区块链上什么也不做,除非有人调用其中的函数。所以 msg.sender总是存在的。

以下是使用 msg.sender 来更新 mapping 的例子:

mapping (address => uint) favoriteNumber;

function setMyNumber(uint _myNumber) public {

  // 更新我们的 `favoriteNumber` 映射来将 `_myNumber`存储在 `msg.sender`名下

  favoriteNumber[msg.sender] = _myNumber;

  // 存储数据至映射的方法和将数据存储在数组相似

}

function whatIsMyNumber() public view returns (uint) {

  // 拿到存储在调用者地址名下的值

  // 若调用者还没调用 setMyNumber, 则值为 `0`

  return favoriteNumber[msg.sender];

}

在这个小小的例子中,任何人都可以调用 setMyNumber 在我们的合约中存下一个 uint 并且与他们的地址相绑定。 然后,他们调用 whatIsMyNumber 就会返回他们存储的 uint。

使用 msg.sender 很安全,因为它具有以太坊区块链的安全保障 —— 除非窃取与以太坊地址相关联的私钥,否则是没有办法修改其他人的数据的。

### require用法

限定每个玩家只调用一次这个函数

答案是使用require。 require使得函数在执行过程中,当不满足某些条件时抛出错误,并停止执行:

function sayHiToVitalik(string _name) public returns (string) {

  // 比较 _name 是否等于 "Vitalik". 如果不成立,抛出异常并终止程序

  // (敲黑板: Solidity 并不支持原生的字符串比较, 我们只能通过比较

  // 两字符串的 keccak256 哈希值来进行判断)

  require(keccak256(_name) == keccak256("Vitalik"));

  // 如果返回 true, 运行如下语句

  return "Hi!";

}

如果你这样调用函数 sayHiToVitalik(“Vitalik”) ,它会返回“Hi!”。而如果调用的时候使用了其他参数,它则会抛出错误并停止执行。

因此,在调用一个函数之前,用 require 验证前置条件是非常有必要的。

### import引入

在 Solidity 中,当你有多个文件并且想把一个文件导入另一个文件时,可以使用 import 语句:

import "./someothercontract.sol";

contract newContract is SomeOtherContract {

}

这样当我们在合约(contract)目录下有一个名为 someothercontract.sol 的文件( ./ 就是同一目录的意思),它就会被编译器导入。

### Storage与Memory

在 Solidity 中,有两个地方可以存储变量 —— storage 或 memory。

Storage 变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 你可以把它想象成存储在你电脑的硬盘或是RAM中数据的关系。

大多数时候你都用不到这些关键字,默认情况下 Solidity 会自动处理它们。 状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。

然而也有一些情况下,你需要手动声明存储类型,主要用于处理函数内的 _ 结构体 _ 和 _ 数组 _ 时:

contract SandwichFactory {

  struct Sandwich {

    string name;

    string status;

  }

  Sandwich[] sandwiches;

  function eatSandwich(uint _index) public {

    // Sandwich mySandwich = sandwiches[_index];

    // ^ 看上去很直接,不过 Solidity 将会给出警告

    // 告诉你应该明确在这里定义 `storage` 或者 `memory`。

    // 所以你应该明确定义 `storage`:

    Sandwich storage mySandwich = sandwiches[_index];

    // ...这样 `mySandwich` 是指向 `sandwiches[_index]`的指针

    // 在存储里,另外...

    mySandwich.status = "Eaten!";

    // ...这将永久把 `sandwiches[_index]` 变为区块链上的存储

    // 如果你只想要一个副本,可以使用`memory`:

    Sandwich memory anotherSandwich = sandwiches[_index + 1];

    // ...这样 `anotherSandwich` 就仅仅是一个内存里的副本了

    // 另外

    anotherSandwich.status = "Eaten!";

    // ...将仅仅修改临时变量,对 `sandwiches[_index + 1]` 没有任何影响

    // 不过你可以这样做:

    sandwiches[_index + 1] = anotherSandwich;

    // ...如果你想把副本的改动保存回区块链存储

  }

}


 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部