Solidity
Solidity是编写智能合约的语言,运行在ethereum虚拟机上。语法类似于JS,它拥有异常机制,一旦出现异常,所有的执行都会被撤回,这是为了保证合约执行的原子性,避免中间状态出现的数据不一致。
官方提供了IDE: remix
下面看一个简单的合约的例子:
pragma solidity ^0.4.9;
contract Helloworld {
function multi(uint a, uint b) returns (uint c) {
uint result = a * b;
return result;
}
}
上面这个函数很简单,调用multi方法进行乘法运算。
基础语法
1.数据类型
- address 以太坊地址的长度,20个字节
- int/uint 变长的有符号或无符号整型。支持以8递增,uint8到uint256。uint 默认为uint256。
- bool 布尔型
- mapping 键值对映射关系,如mapping(address => uint)
-
struct 结构体,如下例子
2.状态变量storage和局部变量memory
两者区别很容易理解,memory可以理解为临时变量,不会记录在链上,而storage是永久存储的。
- 变量定义时默认为storage,而作为函数参数时,默认为memory
contract HelloWorld{
//等价于 string storage public a;
string public a;
//参数等价于string memory _a
function changeNum(string _a){
}
}
- 当函数参数为memory类型时,相当于值传递,storage才是指针传递
contract HelloWorld2{
string public a;
function HelloWorld2(){
a = "abc";
}
function f(){
changeNum(a);
}
function changeNum(string _a){
bytes(_a)[0] = "d";
//由于_a默认为memory,所以_a只是值传递,所以此时修改a的值是不成功的,输出还是abc
//需要把函数参数修改为string storage _a,才能输出dbc
}
}
- 将变量赋值给一个新变量时,新变量的类型由赋值给它的类型决定。
function changeNum(string _a){
//_a默认为memory类型,所以b也为memory
string b = _a;
bytes(_a)[0] = "d";
}
3.函数四种访问权限
函数声明有public、private、internal和external四种访问权限
- 1.函数默认声明为public,即可以以internal方式调用,也可以通过external方式调用。可以理解为能够被内部合约访问和外部合约访问。
- 2.Internal声明的只允许通过internal方式调用,不能被外部合约。而external能够被外部合约访问。
- 3.private和internal类似,都不能被外部合约访问,唯一的不同是private函数不能被子类调用,而internal可以。
如下例子:
contract FunctionTest{
function publicFunc() {}
function callFunc(){
//以`internal`的方式调用函数
publicFunc();
//以`external`的方式调用函数
this.publicFunc();
}
function internalFunc() internal{}
function externalFunc() external{}
}
contract FunctionTest1 {
function externalCall(FuntionTest ft){
//调用另一个合约的外部函数
ft.publicFunc();
ft.externalFunc();
//ft.internalFunc();调用失败,无法调用internal函数
}
}
4.pure、view、constant三种函数定义
当函数有返回值时,可以添加这三种定义,用这三种方式定义的函数都只执行读操作,不会进行编译执行。即用了这三种方式定义的函数,不会执行函数里的逻辑,只会执行一个返回的读操作。所以执行这些函数不需要消耗gas费用。
- pure区别是用于返回非变量,如returns 10;
- 而view和constant用于返回全局变量,两者的区别为新旧版本
contract HelloWorld4{
uint public a = 1;
//由于被constant声明的函数执行读操作,所以a无法被修改
//执行为f(),a依然为1
function f() constant{
a = 3;
}
}
5.函数修饰符
用于以声明方式修改函数的语义,如下例子:
contract HelloWorld{
address public sender;
function HelloWorld(){
//创建合约时将合约创建者赋值给sender
sender = msg.sender;
}
modifier onlyOwner(){
//如果调用合约的人不是合约创建者则throw
if(msg.sender != sender) throw;
_; //占位符
}
//这样a函数就只能被合约的创建者调用了
function a() onlyOwner{
...
}
6.回退函数
fallback function 回退函数,每一个合约有且仅有一个没有名字的函数,往合约发送消息时,会执行该函数。如果合约要正常接受ether,需要加上payable声明。声明后,当有用户往合约转账时,将触发该函数,可以在里面写相应的逻辑。
7.异常处理
Solidity使用状态恢复来处理异常,就是说当抛出异常时将恢复到调用(包括自调用)前的状态。
抛出异常的方式有assert,require,revert,throw。
- assert函数,用于条件检查,只能测试内部错误和检查常量。
//检查内部计算是否会整型溢出
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
- require函数,也是用于条件检查,用于测试调用的输入或者合约状态变量。
function sendHalf(address addr) payable returns (uint balance) {
require(msg.value % 2 == 0); // 只允许偶数
.....
}
- revert 函数用于标记错误并恢复当前调用。
function buy(uint amount) payable {
if (amount > msg.value / 2 ether)
revert("Not enough Ether provided.");
}
- throw 和revert一样,但是throw在0.4.13被弃用,将来会被淘汰。
网友评论