《智能合约开发课》学习8:Solidity的语法知识点

in cn •  7 years ago  (edited)

img最近报名参加了硅谷区块链举办的《智能合约开发课》第二期培训班,根据培训要求,不能透露课程的内容,但我会在steemit上记录我的成长过程。

单纯地学Solidity的语法知识点非常枯燥,而放在一个个的实际例子中逐步深入时,则轻松了许多,当前已经学完了智能合约开发课的第三课,必须把学过的语法点抓紧总结一下。

一、文件名

solidity文件的扩展名为*.sol

二、指定编译器版本

pragma solidity ^0.4.0;

表示源程序在大于等于0.4.0版本的编译器可以正常工作,在大于等于0.5.0版本中的编译器中无法工作。即:

0.4.0 <= version < 0.5.0

关于pragma的详细文档在这里:http://solidity.readthedocs.io/en/develop/layout-of-source-files.html#version-pragma

而版本号之前的“^”符号的含义,来自于npm中的语法

三、数据类型

solidity是静态类型语言,所有变量需要有定义声明。

1)整数

常用的无符号整数类型有uint8, uint16, uint24, ... ,uint256。256个字节的无符号整数uint256可以简写为uint。而有符号的整数则从int8, int16一直到int256。

这些整数经常会用来保存用户的token数量,小心加、减、乘、除运算后的结果溢出,那可是非常惨痛的损失。

uint a = 365;

2)地址

address用来存储以太坊的地址,实际上就是不超过20字节的无符号整数,例如:

address a = 0xdd870fa1b7c4700f2bd7f44238821c26f7392148;

后面的0x开头的一串十六进制数并不是字符串,不需要双引号。而在remix调试程序时,传入的地址参数却需要双引号括起来,新手一开始经常会遇到这个错误。

地址有合约地址和普通的钱包地址两种。

3)结构struct

与C语言非常相似,不用多说。

struct Participator {
    address addr;  
    uint amount;
}

4)数组

Solidity支持定长数组:

uint[5] a;

也支持动态数组:

uint []b;

在动态数组中增加一个元素用push()函数。

b.push(1);

b.push(2);

b.length得到数组的长度,还可以直接修改length来删除元素。

b.length = 1;

5)mapping类型

这种类型相当于其它语言中的哈希表,一开始不太适应,是solidity中非常重要的一种数据类型,以后再展开。

6)var

var并不是表示动态类型,而是让书写更简单,一个值在分配给var变量时,其类型就已经确定了。如果要赋值给其它类型,仍要进行强制类型转换。

7)其它类型

solidity中还支持布尔类型、字符串类型、枚举类型等等。非常神奇,这次的培训课中竟然一直没讲string类型,通常的编程语言都会在第一课介绍"hello world"。可能智能合约是与token打交道,而不是输出字符串吧。

四、函数修饰符

function modifier可以让函数显得更加简洁,比如经常判断一个函数的msg.sender是不是合约构建者时,不需要频繁插入require(msg.sender == owner);这样的语句,只需要定义一个modifier。

modifier onlyOwner {
    require(msg.sender == owner);
    _;
}

而在函数声明的主体尾部加上onlyOwner就可以了。上面的语法中最有意思的是_;这行语句,表示原来函数中的所有语句。当函数中含有return()语句时,替代规则有点特殊。

function test() onlyOwner { 
   // ...
}

payable实际是一个内置的修饰符,表示一个函数在调用时要发送ether。

五、继承

solidity支持多重继承,继承线采用与Python相似的C3 Linearization规则

contract parent {
    // ...
}
contract child is parent {
    // ...
}


抽象合约是函数只有声明,没有具体的实现。

interface与java语言的语法类似,不用多说。

六、多参数返回

在函数的返回值中可以一次返回多个参数,比如:在返回一个数组中的元素的同时,返回它在数组中所在的位置时,这样可以一次给多个变量赋值。

function test() returns (address item, uint index) {
    address []arr;
    // ...
    return (arr[1], 1);
}
address owner;
uint i;
(owner, i) = test();
(owner, ) = test(); //如果不需要第2个参数

七、异常处理

在比较早的solidity版本中都用throw(),现在统统用revert(),可以保证在遇到异常时,回滚到调用前的状态。用require可以写得更简练。

require(msg.sender == owner);

另外的一个容易让人搞糊涂的语句是assert,在C语言中,assert翻译为“断言”,这类语句只在调试时起作用,用来排查软件的重大BUG,这里也是类似。表示程序在执行到这条语句时,肯定会满足其中的情况。如果有异常发生,说明软件肯定有重大的BUG,由于solidity中涉及到转帐等重要操作,assert失败后,会耗光所有的GAS,让交易失败,防止更严重的事情发生。assert常用于数组越界、元素非空的检查上。

而require要检查的是软件可能经常发生的情况,比如给函数中传递的参数时是否满足一定的条件等等。

八、几个全局变量

solidity中内置了msg,block和tx这几个全局变量。

  • msg.value,消息所附带的货币量,单位为wei
  • msg.sig,调用数据的前四个字节,函数标识符
  • msg.sender,当前调用发起人的地址
  • msg.gas,当前剩余的gas
  • block.difficulty,当前区块的难度值
  • block.blockhash(),某个区块的哈希值
  • block.coinbase,当前区块矿工的地址
  • block.gaslimit,当前区块的gas上限
  • block.number,当前区块的序号
  • block.timestamp,当前区块的时间戳,是uint类型
  • now,等同于block.timestamp
  • tx.gasprice,交易的gas价格
  • tx.origin,交易的发起人,完整的调用链

九、可见性

函数的可见性有external、public、internal和private。

状态变量的可见性有public、internal和private,类似于C++语言中的public、protected和private。

external只能修饰函数,说明这个函数只能被外部合约调用。假设函数f()是external,还想在合约内调用,可以用this.f()。

十、delete

delete操作可以用于任何变量,将其设置为默认值0。

对可变数组使用delete,会删除所有元素,其长度变为0。

对定长数组使用delete,则会重置所有元素为0,也可以重置指定位置的元素。

对map类型使用delete,什么也不会发生。

对map类型的一个键使用delete,则会删除与该键相关的值。

本文由币乎(bihu.com)内容支持计划奖励

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

榜样。来到世上就是为了学习来了。

赞!