智能合约基础语言(二)——Solidity源文件布局和合约结构
【智能合约基础语言02期】Solidity源文件布局和合约结构
一、目录
1.1 常见的内置函数
1、pragma版本杂注
2、注释
3、导入源文件
1.2 合约结构
1、状态变量
2、函数
3、函数修改器
4、事件
5、结构体
6、枚举
7、常量
8、控制结构
9、映射
1.3 错误处理
1、assert
2、require
二、Solidity源文件的布局——pragma(版本杂注)
说明:
1、版本要高于0.4.24才可以编译;
2、高于0.5的版本则不可编译;
3、第三位的版本号可以变,留出来用做bug可以修复(如0.4.1的编译器有bug,可在0.4.2修复,现有合约不用改代码)。
▶源文件应该使用pragma进行注释,防止由于编译器升级导致的不兼容问题。
▶源文件可以使用大版本号相同,小版本号高于当前版本的编译器进行编译。
三、Solidity源文件的布局——注释
3.1 单行注释(//)
3.2 多行注释(/*...*/)
3.3 natspace注释
natspec 注释,它们是用三个反斜杠(///)或双星号开头的块(/** ... */)书写,它们应该直接在函数声明或语句上使用。
注意:
natspec注释在编译过程中会被解析。可以不会使用,但是一定要认识,如果使用,一定要保证参数名与函数一致
四、Solidity源文件的布局——import导入其他源文件
▶在全局层面上导入变量和函数,语句将从“filename”中导入所有的全局符号到当前全局作用域中。
▶创建一个新的全局符号 symbolName,其成员均来自 "filename" 中全局符号。
▶创建新的全局符号 alias 和 symbol2,分别从 "filename" 引用 symbol1 和 symbol2 。
▶这条语句等同于 import * as symbolName from "filename";
▶关于路径
引入文件路径时要注意,非.打头的路径会被认为是绝对路径,所以要引用同目录下的文件使用。
五、编译器解析引用文件机制
各编译器提供了文件前缀映射机制。
1、可以将一个域名下的文件映射到本地,从而从本地的某个文件中读取;
2、提供对同一实现的不同版本的支持(可能某版本的实现前后不兼容,需要区分);
3、如果前缀相同,取最长;
4、有一个”fallback-remapping”机制,空串会映射到“/usr/local/include/solidify”。
六、import导入其他源文件——实例
注意:
1、导入其他源文件相当于把多个源文件写到一个源文件中;
2、文件名始终被视为具有/作为目录分隔符的路径
▶./作为当前目录
▶../作为父目录(如果没有/ ,则不认为是当前目录或者父目录)
3、如果不明确指定当前目录或者父级目录,引用将从文件系统根目录开始寻找导入文件,这将导致实际导入的文件与目标文件不同(名字相同内容不同)。
七、合约结构
在 Solidity 中,合约类似于面向对象编程语言中的类。 每个合约中可以包含:
▶状态变量(State Variables)
▶函数(Functions)
▶函数修改器(Function Modifiers)
▶事件(Events)
▶结构体(Structs)
▶枚举(Enum )
(这几个内容本章只是简单介绍一下概念,后续章节会详细讲解。)
7.1 状态变量
状态变量——永久地存储在合约存储中的值。
7.2 函数
函数——合约中代码的可执行单元。
7.3 函数修改器
函数修改器——用来以声明的方式改良函数语义。
7.4 事件
事件——以太坊虚拟机日志工具的方便接口。
7.5 结构体
结构体——可以将几个变量分组的自定义类型(自定义复杂变量的模板)。
7.6 枚举
枚举——枚举可用来创建有一定数量的值的自定义类型。
7.7 常量
状态变量可以被定义为constant,常量。这样的话,它必须在编译期间通过一个表达式赋值。赋值的表达式不允许:
▶访问storage;
▶区块链数据,如now,this.balance,block.number;
▶合约执行的中间数据,如msg.gas;
▶向外部合约发起调用。
注意:
不是所有的类型都支持常量,当前支持的仅有值类型和字符串。
八、控制结构
和其它程序语言一样, 编程中不但需要变量常量存储值, 而且需要编写逻辑, 那么逻辑部分就是由这些控制结构负责的:
1、支持:if,else,while,do,for,break,continue,return,二元表达式;
2、不支持:switch和goto;
3、条件判断中的括号不可省略,但在单行语句中的大括号可以省略。 if(true) do('something');
4、需要注意的是,这里没有像C语言,和javascript里的非Boolean类型的自动转换,比如if(1){...}在Solidity中是无效的。
九、映射
solidity里的映射可以理解为python里的字典,建立键-值的对应关系,可以通过键来查找值,键必须是唯一的,但值可以重复。
定义方式为:mapping(键类型=>值类型),例如
这个映射的名字是balances,权限类型为public,键的类型是地址address,值的类型是整型uint,在solidity中这个映射的作用一般是通过地址查询余额。键的类型允许除映射外的所有类型。 比如记录一个地址里有1000个eth。
十、错误处理
10.1 概述
错误处理是指程序发生错误时的处理方式,Solidity处理错误和我们常见的语言不一样,它是通过回退状态的方式处理错误,在发生异常时会撤销当前调用(及其所有子调用)所改变的状态,同时给调用者返回一个错误标识。(没有try catch 不可能捕获异常)。
10.2 assert()
assert(bool condition)用于判断内部错误,条件不满足时抛出异常。
特点:注意会消耗掉全部的gas
在下述场景中自动产生assert类型的异常:
▶数组下标越界或者小于0
▶被除数为0, 如5/0 或 23 % 0
▶对一个二进制移动一个负的值。如:5<<i; i为-1时
▶整数进行显式转换为枚举时,过大值、负值
▶调用未初始化内部函数
▶调用assert的参数为false
10.3 require()
require(boolcondition):用于判断输入或外部组件错误,条件不满足时抛出异常。
特点:不会消耗gas
在下述场景中自动产生require类型的异常:
▶调用throw;
▶调用require的参数为false;
▶调用外部函数调用时,被调用的对象不包含代码;
▶合约没有payable修饰符的public的函数在接收- - 以太币时(包括构造函数,和回退函数);
▶合约通过一个public的getter函数(public getter funciton)接收以太币;
▶transfer()执行失败。
范例:
10.4 其他异常处理方式
除了可以两个函数assert和require来进行条件检查,另外还有两种方式来触发异常:
revert()、revert(string reason)函数可以用来标记错误,终止执行并回退当前调用。
使用throw关键字抛出异常(从0.4.13版本,throw关键字已被弃用,将来会被淘汰。) 当子调用中发生异常时,异常会自动向上“冒泡”。 所谓冒泡就是从当前函数调用逐层向外触发异常。
本文完,获取更多资讯,敬请关注区块链工程师。