智能合约基础语言(二)——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关键字已被弃用,将来会被淘汰。) 当子调用中发生异常时,异常会自动向上“冒泡”。 所谓冒泡就是从当前函数调用逐层向外触发异常。

本文完,获取更多资讯,敬请关注区块链工程师。

猜你喜欢

转载自blog.csdn.net/liankuaixy/article/details/82759542