00:00
好,那么我们今天的这部分内容其实是对昨天内容的一个补充,也可以说是一个提炼和升华,所以大家可以看到昨天我们上手的时候学solidity是用什么上手呢?我们直接就看一个简单的例子,然后就看这个里边它有什么,它里边有状态变量,有函数方法,有呃,它的构造函数,对吧,Constructor之类的,然后我们就看到一个函数里边它有函数名,有函数参数,有返回值,还有函数类型,所以这些东西我们都是拿一个具体的例子一看就知道了,但是呢,我们可能看到的只是个别的例子,或者说典型的例子。真正在扫地这个语言里边,它其实还有很多很多别的特性,或者说在我们没有接触到的一些地方,它还有很多值得我们去注意的东西,那今天我们其实就是想要跟大家来把这一部分来做一个讲解,让大家对小丽丽这个语言呢有更深刻的一些认识。
01:09
好,我们现在开始啊,所以这部分大家看昨天那部分我们叫简介对吧,所以这部分我们就是的一个深入理解。首先我们来看一下solidity的原文件布局,这就是说我们一上来之后,整个这个solid,呃,Source code的这个原文件里边,我们上面的那些东西是是什么样的东西,我们昨天不是说prama这个东西它是一个杂住吗?呃,这里给出明确的定义啊,Prama是一个版本杂住,所以就是原文件可以被prama版本杂住这个东西所注解,它的注解的意思就是表明要求的编写版本,这个我们大家都知道,这里就是明给出明确的定义,大家有一个理论上的概括就可以,比如说像下面这个有一个向上的小小小尖括号,然后0.4.0 solid 0.4.0,那这个意思呢,它说的就是说要求我们的编译器版本不得低于0.4.0,而且也不允许高于0.5.0。所以它就。
02:24
就是0.4几就是这个意思。呃,这个比较方便的一种一种,呃,就是经常大家看到很多原文件里面会用这种方式,其实就是因为在扫里边大版本的变化其实还是比较比较多的,特别像现在就是0.5.0还没有正式发布,但是我们已经看到已经知道的0.5.0里边的变化相当的多,所以。呃,大家如果要是想要去用0.5 5.0的编译器的话,可以注意到就是里边其实有很多语法细节跟我们现在是不兼容的。
03:05
所以这一点大家一定要稍微注意一下,我们也会最好是以后我们现在的教学基本上还是以就是0.4几的版本来做一个说明的,0.5几的特性我们会稍微就是额外的提一下,但不会更多的去用我们现在的写的原文件,因为我们的编辑起来都是0.4.2几的版本嘛。所以。现在大家一定要考虑清楚自己的版本状态,以后我们还会去升级对吧,大家应该会不停的跟,跟着当前的这个版本去走,所以也希望大家保持这样的一个一个意识和状态,不要就是之后,呃,我们真正到工作实际当中去运用了版本已经是0.5.0了,然后我们发现,诶,我怎么以前写的合约编译都通不过了,所有的东西到处都报错,大家只要有这个概念就可以,我们去查新的文档,看看它有什么变化就可以。另外有一个需要注意的原文件布局,其实我们还没有见到过,就是import。
04:08
这个port其实比较简单,就是大家在其他的一些编程语言里面肯定都见过,对吧,JS里边就很对很很基础的一个引入其他文件的一个方式,音port,那solidliity它所支持的音port的语句呢,它的语法跟ES6是非常的类似的,是什么样的语法呢?我们大概来看一下啊,Inport主要就是这么几种,一种就是这一种,就是直接inport的一个文件名。它表示什么意思呢?就是从这个文件名里边导入所有的全局符号,也就是全局变量,我们在那个里边,它export出来的所有的东西全部进来。这就是最简单的一种用法,那边导出什么,我们这边就导入什么,另外下面的第二种这个用法其实是可能平常是比较常见的一种用法,大家可以看一下啊,这种用法是import芯。
05:07
As,一个sign。From一个文件名。它是什么意思呢?它是说首先S一个C内,那肯定就是新创建了一个变量,对吧,新创建了一个符号,这是一个全局的符号。它的内容是什么呢?它是个什么东西呢?它是一个大的对象。他对象的成员就是来自。他from的那个文件里面的所有导出的对象。所以大家可以看到它是这样的一个逻辑啊,就是把上面那个file name那个文件里面所有的东西都引入进来,然后把它归到一个大的对象里面去,作为它的一个子元素,这种方式在很很就是大家如果看比较复杂的,呃,合约的话,经翅用到这种东西,然后下面一种用法呢,这个可能大家在编程语言里边也是经常见的一种方式,就是我只导入部分。
06:08
前面我们都是导入全部嘛,对吧,下面它就是说,假如说我这里边只要一个single one和single two,只要这两个符号从那个fair号内里边导入进来,我应该怎么写呢?好,我就打一个花括号,把它们括起来,然后inport这些符号,它当然了,我在port进来的时候,如果说什么东西都不加,就是single one single to,那就相当于名字不变,那个里边叫这个名,我这还这么用,那如果说我这个里边还想给他一个别名的话,那可以加上as,就是single one as a,那我这个文件里边,我用它的名字的话,就用这个A,用它的别名来指代这个东西,大家应该熟悉别的编程语言,特别熟悉ES6的话,这个是很简单的啊,都差不多。另外还有一个最后这个是跟ES6不一样的一个语法啊,还有一种额外的用法是import fair name as symbol name。
07:09
这种用法,呃,其实前面说了,就是第二种那个音炮的用法,经常在合约里边能够见到,但是事实上用的更多的可能是第四种这种用法,因为它写的更简单,他们俩的含义其实是一样的。呃,所以就是说他也意思是从这个file name里边,我导出所有的变量,然后把它保存在我这个文件里边,一个叫做simple name新命名的一个对象下面,它是这样的一个逻辑,好,关于英port的这个比较简单,所以我们就是说给它过一遍就可以了,接下来这一部分也是过一遍就可以,但是。呃,我们既然要详细的掌握一门语言吧,它里面基本的数据类型肯定还是要我们至少知道有这些,而且就是有一些细节大家知道的话,要该查的时候到到我们的资料里面来查,对吧?呃,Solid的值类型大家首先能区分的开值类型和引用类型对吧?
08:08
就是值类型的话,就是它本身存储的地方,就是直接是存储的,它的value率就是它的值,而不是说是一个指针之类的东西,引用之类的东西,对大家这个应该是熟悉的,所以大家可以看到有哪些基本的值类型呢?首先就是布尔非常简单出或者日出或者false,对吧?然后就是整形,我们所说的in和u in int是呃有符号的整形,有in是无符号整形,它们表示的。呃,平常我们经常写的u int到底是什么呢?U int其实就是UT256的编程,所以对应的我们也可以直接写int int就代表INT256在扫里边,它比较好的一点就是说支持很多。就是后面带一个数字的关键字来表示它的位数,所以这个用起来就很方便了,对吧?所以它支持什么呢?它支持从UNIT8到UNIT256,以八为单位,以以八为步长吧,这个应该叫对,就是递增对吧,UNIT8 unit16 unit24,这个大家我给大家说一下,就是remix里面这个其实是比较好用的啊,我们随便打开一个,比方说打开这个car的这个文件,我们敲一个啊,大家可以看它的这个自动提示unit,大家可以看下面,其实就是能把所有的keyword,就是关键字都已经列出来了,所以大家看真的是以八做这个递减对吧,它最上面是256,然后248 240,一直到最下边。
09:48
对,86当然可以UN,那就是跟UN256是一样的,所以大家如果要是有这种不太熟悉的语法或者是数据结构的话,直接在mix里边敲一下,我们有这个编译器,它可以实时检查,所以这个是非常方便的一个地方。
10:08
好,我们继续来说其他的一些类型,另外就是呃,昨天我们在写合约的时候,也有同学提到,那你有有整形,我们有一些像金额相关的,是不是还应该有浮点型啊,对,没错,力里边也是支持浮点型的,而且大家看它支持的这个就是呃,用法其实还是挺方便,它用的是什么关键字呢?两个关键字,一个叫fixed。一个叫u fix,也就是说一个是有符号的浮点型,一个是无符号的浮点型,前面加U嘛,跟in是一样的,然后大家注意,除了这个fix和u fix之外,他们就是fix和u fix,它其实是一个特定的限定的这个关键词。它最正常的这种定义,或者说最完整的定义是什么呢?是fix的M的M代表一个数,然后后面X。
11:10
后面是N又代表一个数,就是fix mxn这样的一个一个形式。同样无符号的浮点数呢?就是u fix m xn。那这里M和N代表什么呢?M代表它的类型,整个占用的位数。N代表的是可用的小数位数。所以最常见的fix和u fix它的类型是什么呢?我们大家敲一个看一下啊,它最常见的比方说是fix。128就是总共128位。然后大家看现在他还在提示这个编译错误,对吧。我们如果要是正常敲的话,它应该是不提功偏移错误的,后面跟一个28,大家看这可以可以这样去定义一个,这是一个有符号的浮点数,所以这里我们定义的一个A就是一个有有符号的浮点数,它的全部的长度,数据存储的长度是128位,而它的小数可以有20位。
12:19
所以这是我们这个浮点数的一个定义啊好,那呃,那那我们前面说了那个U就是U256,那我们这里边的fixed和u fixed是是什么呢?这里可以告诉大家,Fixed就是FIXED128。X19的别名。所以它指的是128位总共数据长度,然后19位最大,19位小数的这样的一个浮点型变量。那同样就是如果是u fix的话,它就代表的是u fix128x19是这样的一个定义。
13:00
当然我们平常大家可以看到,我们其实用到浮典型的地方不多,因为我们尽量想把它转成整形,256位的整形其实已经是很大了,对吧,已经能处理很大的数字,能处理很大的精度,所以呃,在这种精度的考量下,可能用整形比用浮点型更好一点,但是大家需要知道,浮点型见到的话就是不要不知道它是什么东西。呃,另外就是这个N的取值啊,M的取值的话,基本上就是八到,呃,应该是256也是可以的,八到256,同时它也是不长是八,必须得被八整除,86 24这种你不能来一个,呃,FIX15这这种是没有的,另外N的取值范围它是零到80,最多80位小数这样的一个定义,多说了几句啊,其实fix用的地方不是很多,然后接下来我们看一个地址类型。
14:02
地址类型其实前面我们都已经给大家强调过很多次,就是它是整个扫里边最特殊,也是为了我们在区块链上以太坊上去去应用,去部署合约,就是写写我们的智能合约,而专门引入的一个类型,数据类型,那它是一个24节的值,也就是存储的就是我们以太坊地址的大小,20个字节,一百一百六十位对吧?那这个之后地址类型我们之后再详细的去解释啊,这里我们只是过一遍,然后还有一种值的类型,就是定长字节数组,定长数据,呃,定长字节数组这个东西呢,它是主要就是以BY词关键字来定义的,大家可以看到就是字节后面加S对吧?字节数组,那它的定义就有BEST1 best2 by one by two这样的,就是一个一个大家可以看到,就是你几个字节都可以定义成一个定长的数据,呃,字节数组。
15:02
一直到BA32,所以大家可以看到,我们经常有时候去定义一个就是定长的字符串的时候,有时候就会定义成BA3232对吧?呃,这里大家要注意一下,就是它里边的。要存储的东西不是我们平常所认为的一个字符串,就是我们输入的UTF8形式的字符串,而是一个pax,对,是一个16进制的一个表示,所以这个地方我们在处理的时候一定要注意类型转换,大家要注意这个坑,当然了,这里大家就就会想到有定长字节数组,那就还有不定长的字节数组,对吧?这个我们等一会再讲。下面还有一一种直类型叫枚举,枚举这个大家其实也比较熟悉啊,在so里边的枚举呢,它跟C是很类似的,也就是他给了我们一种一种能力,就是可以让用户自己去定义自己想要的这种离散的之类型。
16:07
呃,那默认它的这个下面的值是从零开始递增的,就是比方说我们定义一个星期,就是我们定义一个媒体类型是week,然后里面是星期一,星期二,星期三,Wednesday Tuesday这样,那第一个,呃,A Monday Tuesday啊,我这是说的什么?呃,就是那我们定义的定义的第一个枚举类型的值money,那就应该它的值存储表示是零。后面Tuesday存储就是一对吧,这跟我们C语言里面都完全一样,大家如果熟悉媒体类型是没有问题的,最后还有一种特殊的值类型叫做函数。所以就是函数本身也是一种数据类型,一种特殊的值类型,之后我们重点再把这个函数会展开给大家讲很多函数相关的特性,呃,好,这一部分呢,基本上就是这些,然后函数这这里多说一句啊,就是函数的数据类型,它主要说的是什么呢?就是我们在应用这种数据类型的时候,就是我们可以把一个函数赋给一个变量。
17:14
在这种情况下,一个变量它的数据类型就是函数数据类型,大家应该也有过这种应用。除了S里边的值类型之外,另外更重要的一部分就前面值类型还比较好理解,对吧,它都是这种常规的嘛,你只不过就是存储成什么什么形式而已。更难理解一些的可能是就是我们所说的引用类型,在扫里边主要的引用类型有这么三种,一种是数组,就是我们平常所说的RA,那数组呢,它分成两类,一类是定常数数组,一类是就是变长数组,或者说我们有时候会把它叫动态动态长度数组。
18:01
那大家可以看到,就是我们在声明一个数组的时候,可以直接指定长度,指定常度的时候,声明出来的就是一个定常数组,那如果要是不止定常数,呃,长度后面大家都记得就是数组一般都是方括号对吧?那定义的时候,里边如果有一个数字的话,就表明我们定长,如果没有的话,就表明不定长。等下我们再详细的说,这里还有一句,这个可能更更难理解一些啊,下面这个。对于存储型的storage类型的数组来讲,元素类型可以是任意的。而对于内存型的memory类型的数字来讲,元素类型不能是。映射类型。这个什么意思呢?这个呃先先有个概念,之后我们再详细解释啊,这个大概的意思就是说我们的数组大家可以看到存储可以分成两两种类型,存的时候我可以指定它是存在storage里面,我们前面说过,Storage就是一个相当于一个永久的一个存储空间,对吧,以太坊上面永久的存储空间。
19:11
另外一种是memory内存,也可以存在内存里面存在这两种地方。数组的表现,他的行为是不一样。如果存在storage里边,它的类型什么都可以,你存什么都行,但是如果是存在memory里边的话,不能是映射。大家能够想到就是为什么它显示不等式映设啊,那那我们现在先不说啊,因为我们现在可能刚刚接触这个概念,就是还是有一点有有一点复杂,我们之后详细展开之后,大家再回回过头来去思考一下这个问题,好,除了数组这种引用类型之外,还有两个引用类型,一个叫结构,一个叫映射,结构比较简单,这个跟我们在C里边,或者说其他的一些,就是语言里边大家熟悉的那种结构体是一样的,就是关键字就是structure,呃,那定义的时候呢,就是用户可以自定义一个一个数据类型,这个数据类型是一个,就好像是一个一个打包之后的数据类型。
20:17
一个结构体里边可以包含各种各样的元素,每个元素呢,又可以是不同的数据类型,等一下我们建它的一个例子,大家就肯定就知道它跟C或者其他的语言一样啊,最后是mapping mapping有时候我们把它叫做映射,一般叫做映射啊,可能看大家习惯,大家习惯也会把它叫做什么叫做。叫做什么字典是吧?哦,这个字典的话,呃,在在那个Java或者是其他的一些语言里边经常会有这个字典数据类型,呃,跟我们这里说的映射。很类似,但是又有点不一样,大家可以看到,就是我们可以把映射当成一个哈西饼。
21:06
就是它的P啊,对应的就是值是存在它的那个哈希,指定在那个位置上哈希数据的,对吧,用散列算法把它指定到一个对应的存储空间去,这时我们所说的哈希表,但是其实在以太坊上的映射跟我们传统意义的哈希表又不一样。具体的差别我们还是到后面到的时候再说啊,他在实际的初始化的过程当中呢,会去把每个可能的K。都会创建出来。然后把它映射到字节的形式全是零的值,也就是大家看到这个我们创建一个mapping的时候,它默认的里面的值是什么呢?值都是零,大家可以看就是整个solid,这个是比较简单的一点,就是默认值,这个东西没有特别的复杂,基本上你如果不指定的话,都是零。好,呃,接下来我们看一下。
22:04
接下来我们就是一个一个详细说了,可能这部分很枯燥对吧,我们前面枯燥的东西大家就先大概的看一看,之后我们有具体的合约的例子的时候,大家去用可能会比较更熟悉一点,呃,这个地址类型这里呢,也是必须要跟大家说一下,因为这个涉及到。0.5之后的一些改变。目前来看的话,大家用地址类型的时候,可能觉得很简单对吧,就是我不管是一个外部账户UUA还是一个合约账户,我直接都可以拿到他的地址,我们一般用的时候就是address后面一个括号就可以拿到,对吧?你传入一个合约或者是传入我们的messages send直接就可以拿到他的地址,就是相当于相当于是。用address这个数据类型对它做了一个强制的类型转换,数据类型转换我们拿就就可以拿到它的地址了,这里要跟大家说的一点是在0.5之后。
23:09
地址类型会分为address和address配偶两种类型。所以在那之后呢,只有address payable类型的地址才可以去调用它的transfer和send的成员变量。所以大家还记得吗?我们经常会用比方说,呃,某一个地址后面跟transfer,然后去去发发币对吧?呃,那另外还有一个sand sand可以认为是transfer的一个一个底层版本啊,就是差不多的意思,也是发币的意思,所以。大家注意,现在我们可能都是随便用的,那到0.5之后就要注意了,必须是payable的地址类型才可以有这个方法,那两者的区别和转换就是很简单,Payable嘛,那既然它是可以支付的这种类型,就是只有这种类型我们才可以给他发语态,而如果要是普通的dress类型,那就不可以了。
24:11
另外大家注意,这两种之间,它是允许去做数据类型转换的,允许的是从payable address可以转换的address,这个是可以影视类型转换,而反过来的话是不可以的,也就是说我们一个普通的address想要变成一个payable的address是不行的。甚至你直接去做显示类型转换都不可以,就是我写一个address payable后面打括号不可以,而且是特别就是就是事实,事实上是没有这种用法的,是不能address payable后面讲括号去做类型转换的,没有这种用法,那他要做类型转换的时候,怎么怎么去类型转换呢?他就得绕一下,用什么做媒介呢?用U160。
25:00
大家知道一个地址,不管是payable还是非不是payable,它的最根本上的类型其实都是一个24节的一个一个值对吧,一个数,那我们就可以把它当成一个160位的无符号整形。那通过这个160位的无符号整形,它是可以连接pay和普通的dress。大家的这个这这一块的东西,就是可能我们现在暂时还用不上,呃,就是所以我们只是先给大家做一个了解,就是到0.0.5的时候,大家如果看到了各种各样奇奇怪怪的东西,不要觉得慌,这个其实就是现在已经已经定下来,就到时候一定会是这样的,所以大家先有一个心理预期就可以。呃,另外就是说现在的大家用到的版本合约和地址是一回事,就完全是一回事,我们都说了,就是EVM在处理它们两者的时候没有任何的区别,但是从0.5.0版本起,他们两个会有区别。
26:08
就是在我们目前的版本里面,合约是直接继承地址类型的,所以合约可以认为就是一个地址,那从0.5.0开始,合约不再由地质类型直接派生。呃,但是呢,如果合约它有一个payable的回退,回退函数的话,那它就可以显示转做显示类型转换,可以转换成address payable或者。显示类型转换成address也是可以的,因为我们知道address payable是可以转换成address对吧,所以这个级别是比较低的,它可以随便转换成address,呃,大家就是可以看到现在的扫的发展方向,发展趋势,其实是要越来越严格的限制大家对这些地址和这种交易的运用的,这也是出于安全性的考虑,就你如果要是我们知道一个合约,如果要是没有payable回退函数的话,我们就不能转吧,一开始我们的水龙头函数,大家还水龙头合约大家还记得吗?对,我们一开始就根本转不了钱,给他转不了钱,必须要加入一个payable的回回推函数才可以,所以大家看这些限制都是为了安全性考虑。
我来说两句