Solidity(2)

第二章 映射(Mapping)和地址(Address)

  • Address:以太坊区块链由account(账户)组成。一个账户的余额是以太(在以太坊区块链上使用的币种),可以和其他账户之间支付和接受以太币。每个账户都有一个唯一的标识符——“地址”。
  • Mapping:映射是除结构体和数组外,另一种在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总是存在的。

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];
}

第四章 Require

require使得函数在执行过程中,当不满足某些条件时抛出错误,并停止执行。
Solidity并不支持原生的字符串比较, 我们只能通过比较两字符串的keccak256哈希值来进行判断。

function sayHiToVitalik(string _name) public returns (string) {
  // 比较 _name 是否等于 "Vitalik". 如果不成立,抛出异常并终止程序
  require(keccak256(_name) == keccak256("Vitalik"));
  // 如果返回 true, 运行如下语句
  return "Hi!";
}

第五章 继承(Inheritance)

contract Doge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string) {
    return "Such Moon BabyDoge";
  }
}

由于BabyDoge是从Doge那里inherits(继承)过来的。这意味着当你编译和部署了BabyDoge,它将可以访问catchphrase()anotherCatchphrase()和其他我们在Doge中定义的其他公共函数。
多重继承用逗号隔开。

第六章 引入(Import)

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

import "./someothercontract.sol";

contract newContract is SomeOtherContract {

}

第七章 Storage与Memory

  • Storage变量是指永久存储在区块链中的变量。
  • Memory变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。
  • 状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。
  • 手动声明存储变量主要用于处理函数内的结构体和数组。
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;
    // ...如果你想把副本的改动保存回区块链存储
  }
}

第九章 更多关于函数可见性

publicprivate属性之外,Solidity 还使用了另外两个描述函数可见性的修饰词:internal(内部) 和 external(外部)。

  • internalprivate相似,只不过如果某个合约继承自其父合约,这个合约可以访问父合约中定义的“内部”函数。
  • externalpublic相似,只不过这些函数只能在合约之外调用,即他们不能被合约内的其他函数调用。
contract Sandwich {
  uint private sandwichesEaten = 0;

  function eat() internal {
    sandwichesEaten++;
  }
}

contract BLT is Sandwich {
  uint private baconSandwichesEaten = 0;

  function eatWithBacon() public returns (string) {
    baconSandwichesEaten++;
    // 因为eat() 是internal 的,所以我们能在这里调用
    eat();
  }
}

第十一章 使用接口

如果我们的合约需要和区块链上的其它合约会话,则需要先定义一个interface接口。
例子:

//存储幸运号码并与以太坊地址相关联
contract LuckyNumber {
  mapping(address => uint) numbers;

  function setNum(uint _num) public {
    numbers[msg.sender] = _num;
  }

  function getNum(address _myAddress) public view returns (uint) {
    return numbers[_myAddress];
  }
}

现在假设我们有一个外部合约,使用 getNum 函数可读取其中的数据。

contract NumberInterface {
  function getNum(address _myAddress) public view returns (uint);
}

我们可以在合约中这样使用:

contract MyContract {
  address NumberInterfaceAddress = 0xab38...;
  // ^ 这是FavoriteNumber合约在以太坊上的地址
  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
  // 现在变量 `numberContract` 指向另一个合约对象

  function someFunction() public {
    // 现在我们可以调用在那个合约中声明的 `getNum`函数:
    uint num = numberContract.getNum(msg.sender);
    // ...在这儿使用 `num`变量做些什么
  }
}

通过这种方式,只要将合约的可见性设置为public或者external,就可以与以太坊区块链中的任何其他合约进行交互。

第十二章 处理多返回值

function multipleReturns() internal returns(uint a, uint b, uint c) {
  return (1, 2, 3);
}

function processMultipleReturns() external {
  uint a;
  uint b;
  uint c;
  // 这样来做批量赋值:
  (a, b, c) = multipleReturns();
}

// 或者如果我们只想返回其中一个变量:
function getLastReturnValue() external {
  uint c;
  // 可以对其他字段留空:
  (,,c) = multipleReturns();
}
posted @ 2020-11-19 13:02  又又又8  阅读(317)  评论(0编辑  收藏  举报