地址
以太坊的每个账户都有一个地址,这个地址就是这个账户的标识,类似这个样子:
0x3C7f1E9B49B2f7c92e25224199d05D5Cb6923824
映射
映射是以太坊中另一种存储和组织数据的方法,映射本质上是存储和查找数据所用的键值对,我们看一个例子:
mapping (uint => string) userIdToName;//这个例子中我们可以通过 id 去存储或查找用户名
msg.sender
msg.sender 是 solidity 中的一个全局变量,他表示的是当前调用者(或智能合约)的地址
mapping (address => uint) favoriteNumber;
//设置一个映射,键是address,值是uint
function setMyNumber(uint _myNumber) public {
// 写个函数来设置favoriteNumber
favoriteNumber[msg.sender] = _myNumber;
// 设置favoriteNumber映射,将_myNumber存储在msg.sender名下
}
function whatIsMyNumber() public view returns (uint) {
// 写一个查询favoriteNumber的函数
return favoriteNumber[msg.sender];
// 若调用者还没调用setMyNumber,则值为0
}
require
可以通过 require 来做一些限制,比如 _name 要等于 yichen 才能继续执行,否则报错:
function test(string _name) returns (string){
retuire(keccak256(_name) == keccak256("yichen"));
//solidity 不支持字符串直接比较,所以这里用散列值比较
return "hello";
}
如果调用的时候是 test("yichen"); 就会返回 hello,否则报错
继承(Inheritance)
当代码很长的时候我们可以把它们拆分成不同的合约,通过继承来获得其他合约的功能
contract welcome {
function hi() public returns (string) {
return "hi!";
}
}
contract welcome2 is welcome {
function hello() public returns (string) {
return "hello";
}
}
引入(Import)
solidity 也支持 import(solidity 文件后缀是 sol)
import "./sayhello.sol";
Storage与Memory
solidity 中有两个可以存储变量的地方 Storage 与 Memory
Storage 变量是永久的存储在区块链中的变量
Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除
一个比较好的比喻是:Storage 理解为硬盘上存储的数据,Memory 理解为内存上的数据
状态变量(在函数之外声明的变量)默认为 Storage 形式,并永久写入区块链
在函数内部声明的变量是 Memory 型的,它们函数调用结束后消失
还有一些特殊情况,需要手动指定存储类型,比如:处理函数内部的结构体和数组
更多函数可见性
函数声明 private 之后,哪怕是继承这个合约的子合约都不能调用,所以可以使用更好的方法 internal
用 internal 声明的函数,继承了这个函数所在合约的子合约可以调用这个函数,同时又限制了其他人随便调用
external 声明的函数只能在合约之外调用,不能被合约内的其他函数调用
接口
如果我们想要与其他合约进行交互的话,需要声明一个接口
比如上面的那个最爱的数字的合约
contract LuckyNumber {
mapping (address => uint) favoriteNumber;
function setMyNumber(uint _myNumber) public {
favoriteNumber[msg.sender] = _myNumber;
}
function whatIsMyNumber(address _myaddress) public view returns (uint) {
return favoriteNumber[_myaddress];
}
}
如果我们想要在另一个合约中调用它,来调用者的数字
首先要定义一个接口,可以对比看一下,接口与合约不同之处在于我们只声明了要交互的函数而且没有函数体
编译器就是靠着这些特征识别出这个接口的
contract NumberInterface {
function whatIsMyNumber(address _myAddress) public view returns (uint);
}
使用接口
只要我们的合约是 public 或者 external,就可以与其他合约进行交互
NumberInterface numberContract = NumberInterface(LuckyNumber合约的Address);
// 现在变量 numberContract 指向另一个合约对象
uint num = numberContract.getNum(msg.sender);
//把我们的 favoriteNumber 赋值给 num
if语句
if (keccak256(_name) == keccak256("yichen")) { hello();}