Mapping
映射(Mappings):类似于哈希表。mapping 中任何一个可能的 key
都对应着一个 value
,它的默认值是default-value 。底层用的不是使用链表 + 数组实现的,不需要扩容。value 引用存储在 keccak256(key)
表姐地址,在 storage 上存储,理论无限大。这也导致了,无法原生地遍历 mapping。另外 mapping 只能做状态变量,不能做本地局部变量。
语法
// 声明映射
// key 类型包括: bool, int/uint , address, string...
// value 类型包括: any type
mapping(address => uint) balances; // 状态变量
function() {
mapping(address => uint) balances; // 报错。本地局部变量报错。
}
// 成员赋值
balances[0x1] = 1;
// 成员取值
balances[0x1] // 1
balances[0x2] // 默认值 0
balances[0x3] // 默认值 0
可视度
可视度(Visibility): 可视度不是说别人无法用肉眼无法看到,智能合约部署在区块链上,代码任何人都可以看见。可视度指的是,决定函数或者状态变量的可以被哪些智能合约可见和调用。
-
public
: 所有智能合约可见 -
external
: 只能被外部合约或者外部调用者可见 -
internal
: 外部合约不可见,当前合约内部和子类合约可见 -
private
: 只有当前合约可见
可以用一个例子来解释,什么是外部合约、外部调用者、当前合约内部、子类合约。
有三个合约,Child
、 Parent
和 OutSide
。其中 Child
继承 Parent
, OutSide
和另外两个合约没有直接关系。
- 外部合约可见: `Child` 的函数可以调用 `OutSide` 的函数。
- 外部调用者可见: 在 remix 的 run 面板中 create `Child` 合约后,可以调用。
- 当前合约内部可见: `Child` 的函数可以调用 `Child` 自身的其他函数。
- 子类合约可见:`Child` 的函数可以调用 `Parent` 的函数。
Child
、 Parent
和 OutSide
都有以下四个函数:
function publicFunc() public {}
function externalFunc() external {}
function internalFunc() internal {} // 不可调用
function privateFunc() private {} // 不可调用
// `Child` 中的函数名都加了 `self` 前缀,和 Parent 中的函数做区分。
函数可见性:public
(default) , external
, internal
, private
。
具体示例代码如下:
pragma solidity ^0.4.14;
import "./parent.sol";
import './outside.sol';
contract Child is Parent{
// 返回一个值
function testOutside() {
Outside o = new Outside();
o.publicFunc();
o.externalFunc();
// o.internalFunc(); // 报错。Child 不能调用 OutSide 的 internal 函数。
// o.privateFunc(); // 报错。Child 不能调用 OutSide 的 private 函数。
}
function testParent () {
publicFunc();
// externalFunc(); // 报错。Child 不能调用 Parent 的 external 函数。
internalFunc();
// privateFunc(); // 报错。Child 不能调用 Parent 的 private 函数。
}
function selfPublicFunc() public {}
function selfExternalFunc() external {}
function selfInternalFunc() internal {} // remix 不可见。外部调用者不能调用 internal 函数。
function selfPrivateFunc() private {} // remix 不可见。外部调用者不能调用 private 函数。
}
状态变量可见性:public
, internal
(default) , private
没有 external
。
状态变量可见度和函数可见度非常相似,只有一点需要特殊说明。当在状态变量上添加可视度时,编译器会给状态变量添加个 getter
函数,方便外部直接获取。
使用 remix 创建以下合约时,会出现一个 data 函数,点击该函数就可以获取到 data 的值。
<图>
继承(待补充…)
函数修饰器
函数修饰器(Function Modifiers): 函数修饰器可以改变函数的行为。可通过 _
来控制修饰器的执行时机。
在 Example1 中,通过 modifier
来抽象出检查条件的代码,并修饰 input2
。让 input2
实现和 inputs2
一样的行为。其中 _
可以简单的理解为,do something
代码在 modifier
之后执行。
contract Example1 {
address owner;
function Example() public { owner = msg.sender; }
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function inputs1() {
require(msg.sender == owner);
// do something...
}
function inputs2() onlyOwner {}
}
例如:函数修饰器可以在执行自动执行指定语句。inputs1
和 inputs2
在行为上是等价的。
在 Example2 中,通过 modifier
来抽象出状态变量自增的代码,并修饰 input2
。让 input2
实现和 inputs2
一样的行为。其中 _
可以简单的理解为,do something
(不包括 return) 代码在其之前执行。
contract Example2 {
// 省略 ...
uint output;
modifier increase return(unit) {
_;
output++;
}
function change1() return(unit) {
// do something...
output++;
return output;
}
function change2() increase {
// do something...
return output;
}
}
Safe Math 和 Library(待完善…)
因为 Solidity 数字大多数是和钱有关的,所以在加减乘除的四则运算时,发生上溢或下溢是非常危险的。
contract Test {
uint8 public a = 0;
function set () {
a -= 100;
}
function set2 () {
unit8 c = a - 100;
assert(c < a);
a = c;
}
}
-----
set() // a = 156 整型溢出
import './SafeMath.sol'; // 引入 unit8
contract Test {
uint8 public a = 0;
function set () {
a = SafeMath.sub(a, 100);
}
}
import './SafeMath.sol'; // 引入 unit8
contract Test {
using SafeMath for uint8; // 将 SafeMath 库里的方法,赋予了 uint8 类型。
uint8 public a = 0;
function set () {
a = a.sub(100);
// a = SafeMath.sub(a, 100);
}
}
其他
函数(function)声明:函数是合约内代码的可执行单元。
contract SimpleStorage {
function simpleFn() {
}
}
函数返回值
- 返回一个或多个参数
- 直接赋值返回的命名参数,并返回
// 返回一个值
function oneParameter() returns(uint){
return 1;
}
// 返回多个返回值
function twoParameters() returns(uint, uint) {
return (1,2);
}
// 命名参数直接赋值
function namedParameter() returns(uint foo, uint bar) {
foo = 1;
bar = 2;
}
// 获取返回值
function get() {
uint one = oneParameter();
var (two1, two2) = twoParameters();
var (named1, named2) = namedParameter();
}
本文由【区块链研习社】优质内容计划支持,更多关于区块链的深度好文,请点击【区块链研习社】简书专栏:区块链研习社简书专栏