00:00
好,我们上节课说到了字符数组,定长的字符数组,那我们知道从BAS1到BAS32,那所有的长度它都是定好的,那这个点LA属性返回的就是它固定的这个长度,那大家注意这个是一个只读的属性,既然它是定长嘛,所以这个点length肯定是不能改的,所以大家要注意这一点。另外还有一个类型叫做变长的字符数组,那这个类型呢,就属于引用类型了,它就已经不属于值类型了,为什么呢?因为变长嘛,我们其实不能直接指定一块区域就告诉他宇宙存储在这里,所以它一定是用到了别的一些方法去做存储,比如说我们说的哈希表的方式,对吧,我把它哈希出去,来一个值哈希出去,来一个值哈希出去,呃,在这里边呢,变长的字符数组主要是两类。
01:00
一类叫bits,一类叫string,它俩的区别其实很简单,就是bits是hes。字符串,然而G呢,它是UTF8编码的字符串,那在这个里面大家可能就想到我们一般定义数组的时候,不是比方说如果它的基基本类型是BAT的话,那定义数组不应该是BAT后面一个方括号吗?是不是这样啊,对,没错,就是BA后面放括号也是一个变长数组的定义方式,但是呢,呃,它基本上跟BY大家可以认为是差不多的,但是在实际应用的过程当中。它占用的空间往往会比BYS要多,所以我们一般情况是只用BY,不用那个BY子方括号那种模式去定义变长数组,就是提到变长字符数组的时候,一般就是best和string这两个,所以这个再跟大家多说一句,好,接下来我们看一下枚举,枚举大家一看这个类例子,大家其实就就发现跟C非常的类似对吧,就非常的直观,就是直接一个呃,In,然后state,比方说定义一个状态的枚举类型,Create locked inactive,那它对应的值就是create created就是零,Locked就是一,呃,Inactive就是二,其实就是这样一个,一个相当于我们自己定义的一组常量值,大家都是整形的,这里我们简单自己来实现一个,大家看一下吧,大家可以跟。
02:41
是我一起来敲啊,我们的test不是test啊,刚才在car里面做的测试啊,好,我们在这里边再去,比方说定义一个枚举类型,比方说我们定义一个叫做weekday吧,Weekday,然后这样一个类型里边会包括比方说我们,呃,一般美学类型就不会把它弄下来了,对吧,一般我们就直接跟在后面就可以,比方说我们有Monday Tuesday,好,我就简单写几个吧,星期三怎么写来着?哎,不会写了,不写了啊呃,大家可以看到我如果在这儿写的话,这个会报错。
03:38
这是为什么呢?哎,我是写错这个关键字了吗?应该没有写错是吧,但是为什么我在这儿写会报错呢?对,因为枚举类型的定义,这个其实是我们数据类型的定义,不应该放在函数里面去做这件事情,对,我们可以在外面去做这样的一个数据类型定义,所以大家看到就是函数内和函数外,注意一下这个就是如果要是说我们看到这种很奇怪的这种语法错误的时候,就可以去考虑一下我们是是否它的这个定义的位置有问题,像我们的状态变量,还有枚举类型的定义,还有之后我们要讲的结构体,结构类型的定义全部都是在外边的,就是在我们的合约整个这个它下属的这个划符号里面,而不要放到我们的函数里面去,那我们用这个微的时候怎么用呢。
04:40
那那其实也很简单啊,大家应该记得就是呃,在这个C里边的调用,比方说我们可以定义一个weekday的一个一个一个变量,那么它的名字就可以定义成weekday.monday大家可以看到我们可以这么去用,对吧,就是我们定义一个变量,然后它的值就等于这个枚举类型里边的某一个值,所以呃,这里它是用报这个,这个错啊,好,我们先定义了这个之后,然后我们把它return去看一下它的值到底是个什么东西啊,这个不能是啊,我们把它定义成应该是八看一下,好,这个不行。
05:35
所以这个我们还是不能直接这么看,我们做一个强制类型转换试一下,这个确实没有没有这么做过可以啊,好,我们把它的这一个拿出来枚举类型,自己定义的这个值去做一个强制类型转换,转换成一个整形,然后我们跑一下看看。好。
06:01
好,他返回的是零,这个这个我们不知道是怎么回事,可能那我们还是加个东西吧,呃,我随便写啊,有可能写错了Wednesday,好,那我们这个时候去弄一个Wednesday放在这里,大家预计他应该是返回一个什么。二对吧,哎,看返回的是二,所以大家看这就是我们枚举类型,它里边其实就是01234按顺序来的一个整形值,但是这里注意大家看,就是我们直接去返回的时候,当成U音去返回的时候还不允许,所以他认为这个它是枚举类型里面的值类型。它还不能直接返,就是当成去返回,所以我们要做一个就是显示的数据类型转换,大家这样去做它好,呃,这个就是比较简单,就是我们试一下,大家就就清楚它是怎么回事了,所以说好,接下来我们来看。
07:12
哦,就是这里多说一句,就是说那个所有的它的枚举类型,这里定义好的这些东西都可以显示。数据类型转换成任意的整形,就刚才我们是直接转换成UN了,那我们这里如果要是改成UNIT8或者我们16吧,平常用的少对吧,这也是一样对吧,我们可以删掉部署一下,大家可以测试。都是没有问题的,因为你的16,所以它可以转换成任意的整形,好,呃,另外强调一点就是枚举这个还是有要求的,就是我们定义了枚举类型的时候,里边至少至少要有一个成员,不能里面一个都没有,所以就不能是空的一个媒体类型,好媒体类型比较简单啊,接下来我们来看数组,数组这这一部分可能会比较麻烦一点,它涉及到的东西会比较多,呃,我们一点一点来看,首先我们整体做一个做一个介绍。
08:22
我们看呃,首先这这一部分定义其实是比较简单的啊,就是大家都很熟悉了,固定大小K和元素类型是T这样的一个数组。它是怎么写呢?就是T方括号K和别的语言都一样,对吧?然后我们在定义动态大小的数组的时候,也就是说变长数组的时候,用的就是T直接后面根方括号不不加长长度大小,那它就是一个动态大小的数组。这个应该也跟其他的编程语言很接近,对吧?那大家注意接下来就是不一样的东西了,看一下有五个U动态数组组成的数组,那这一我们在别的语言里面可能有时候会把它定义成二维数组,对吧?就是这是一个数组,首先这是一个数组,它的元素有五个。
09:18
那每一个都是一个动态的类型的数组,就是动态长度的数组,那这样一个数组定义的时候怎么定义呢?是U方括号里边没东西,后面跟一个方括号。这个至少跟C语言不一样啊,大家如果熟悉C语言的话,注意不要搞混,C语言里边如果定义这样的数组怎么定义。就是五个五个这样长度大小可变的数组。构成的数字,这个怎么定义?二位数字怎么定?C语言里面是u in的后面先是五,然后后面跟一个放括号对吧,所以大家注意这个是反过来的。
10:02
呃,所以呃,这个这个很难说到底是哪个更反反直觉吧,就是我自己的感觉,就是说大家如果要是有那样的习惯的话,在这里只要注意一下,就是不要跟他搞混就可以了。呃,就是这里的定义,我觉得其实这个可能从直觉上讲可能更合理一些,就是说我定义的前面的这一部分,就指的是我的最小的那个单位,这是一个动态数组。然后后边的这个呢,表示我的大一些的那个是一个五个的一个一个数组,但是C的话就不一样,C因为它是跟那个访问的时候那个方式一样的,因为访问的时候前面这个下标只带比较大的那个类型,对吧,大的那个数字,然后下面是小的,所以扫这么定义的话,可能会让大家有一点绕,就是呃,然后大家看到就是访问的时候呢,它又跟C那边一样了,大家看啊,就是如果要访问第三个动态数组里边的第二个有,这就是前面你那个不是五个动态数组吗?我现在要访问其中的第三个。
11:10
然后它本身又是一个动态数组,我要访问动态数组里面的第二个,那怎么访问呢?就是X21,第三个呢,应该是二嘛,对吧,然后里边的第二个那是一,所以它又跟C的访问方式是一样的,这个是一样的,但是就是前面定义的方式反,所以可能是有点有点绕对吧,有点就是我也觉得这个可能设计的时候,呃,他会觉得C的那种觉得可能比较反直觉吧,就就他把C的这个又改过来了,但是我们已经熟悉C的那种定义,就会觉得有点难受啊,大家知道就可以,然后注意在扫利里边如果越界访问数组,会导致直接导致调用失败,然后会回退,呃,这一点也是就是就是有有说法,就是对S比较诟病的一点,就是这一点。
12:04
整个这个安全性上没有一个合理的检查机制,大家往往在程序里边去做访问的时候,其实是不知道到底是到了哪里的,然后然后就发现他直接数组越界,直接就报错了,所以呃,就是有些人会说,就是小艺这个地方设计上还是有一些不完善,但是大家只要注意就行,就是访问数组的时候不要越界访问。比方说一个数组,我们定义的这个A8,它是一个定长的,呃,就是我们随便定义一个假如是U的一个一个数组,UNIT8这样的一个数组,如果我们直接用下标九去访问,或者我们直接用八下边八去访问。访问A8或者A9的时候就会直接报错回退。大家一定注意这个数组越界,另外就是说在这个数组里边如果要添加新元素,首先如果是动,如果是这个固定长度大小定长的数组的话,那大家想它其实里面就不能再再加锌元素了,对吧,它的长度是固定的啊,所以这个是不存在这样的,如果要添加新元素,那就肯定是动态大小的数组,用什么方法呢?
13:22
两个就,而且是只有这两种方法,一种叫这个数组名字后面点push,然后把元素push进去。或者还有另外一种方法是直接点LAS给它赋值。给它赋一个更大的值,这两种方法有什么不一样呢?那就要说到就是length和点push方法这两个东西到底是个什么东西了?LS这个属性是所有的数组源数、数组数据类型都有的一个元素。
14:03
那我们前面看到了,如果是固定大小的数组的话,点length就返回的是它设定好的那个大小,而且这个点LA是不能改的,那如果是动态长度的数组的话,同样点LAS也是返回它的当前的长度,那但是呢,它的长度到底能不能增大呢?这个还要考虑。他到底是不是。我们的storage类型就是大家前面跟大家说过,就是我们的数据存储是可以存储在它固定的那个storage里边,也可以存储在内存里边,这个时候它就不一样了,如果要是存在storage里边,那点就可以变,如果存在memory里边,那它是不能变的,所以这个就是就是又又会有很多很多的限制啊,我们到后面就是专门去要去专门去讲一下这个storage类型和memory类型,呃,那点push这个方法呢,它主要是变长的storage数数组也是必须是storage存储类型,可以有这个点push方法,所以所以大家可以看到,那照这么说的话,Memory其实里边它。
15:27
要创建一个数组的时候,尽管可以创建动态大小的数组,但其实它的长度也得给定,为什么呢?因为我们分配内存吧,你一开始不知道要给多少内存,这我们是没法玩的,那内存很很容易泄露,所以我们一开始一定要指定,就是memory里面去定义数组的时候,是肯定是要指定长度的,当然有可能这个长度本身这个值还不确定,就是我们可以把这个长度当成一个变量,所以这种情况下是可以实现动态大小的,但是一旦指定之后,它就是这么大。
16:03
所以这是我们所说的这个memory类型和storage类型的不同啊,所以大家看就是变长的数组和bits。是有这个点push方法的,注意啊,String没有点push方法也有限制。但是大家现在一下子可能也都记不住这些,大家反正就知道它数组里边呢,呃,就是添加新元素的时候,动态数组添加新元素的时候两种招,一种是点LA,直接给它赋值增大,一种是点push。方法,这两种方法又有各种各样的限制,大家忘记的时候回过回过来查,大概就是这样啊,呃,类似的就是除了这个push方法之外呢,类似的数字那当然有push push是近近战对吧,推进战,那就应该还有一个pop,呃,先说一下这个push是什么意思啊。Push就是要把一个新的元素直接加入到这个数组里面,加到哪里呢?加到末尾。
17:06
这个本来是一个方法,它有返回值,返回的就是对当前数数组的长度。那同样就还会有一个pop方法,Pop方法跟这个push方法几乎是一样的啊,就是只不过它的应用就是相当于把数组最末尾的一个元素给去掉,相当于是删除末尾的元素,好这是我们对数组的一个直观的理解,好接下来我们就来看一个例子,这个数组的例子,好的,先这么,这样可能看的清楚一点,因为这个在remix里边也大家直观的看不到什么执行结果,因为它也没有返回什么的吧,它主要是这一段逻辑也比较简单,大家直接看这个代码就可以,我们来阅读一下这个这个代码它说的是什么?CC定义了一个,定义了一个合约,然后里边直接就定义了一个方式,然后这个方式后面大家已经见过好几次了啊,这个Q就表示它是,就是相当于什么都没,什么都没改对吧,也没有状。
18:14
变量什么的,什么都没改,是它是个纯函数,它里边做了什么操作呢?大家看定义了一个U的变长数组,对吧?这是一个U的变长数组,然后等于A,而呃,不是,就是定义的名称是A,然后它的存储位置,存储类型是一个memory类型,我们前面说了memory类型其实是。一开始就得指定它的大小的对吧,所以大家看到这个memory类型得怎么怎么用啊,所以一开始指定之后就必须初始化,等于new一个。动的,尽管前面指定的是呃,就是动态的大小,但后边大家看new的时候用的这个方法就是要创建一个U数,然后跟上一个七,跟上一个大小,那所以这一句我们其实就是为A这样的一个u int数组给它分配了七个对应的U的存储空间。
19:23
是这样对吧,尽管还没有复值,但是已经把它存储空间分配好了啊,那大家再看我们还可以就是BABA也是一样嘛,也是一个数组嘛,而且是一个动态大小的数组嘛,BAS也可以定义一个memory类型的变量BASB它就一样,也是new,定义的时候一定要给它分配内存空间。New bys,然后后面这个就可以我们不给一个固定长度,给一个Le LA,那这个是什么呢?是我们传进来的一个参数,所以这个参数只要给定,那其实这里的B分配的空间也就指定了,对吧,也就是固定的,所以说library的动态调整是可以用这种方式去调整的,当然如果在之前就是学过C,然后对C里边的这种,呃,动态数组的这种这种应用的话,比较熟悉的话,其实可以发现这个其实就跟C里边的实现是一样的啊,C里面怎么实现一个动态数组,那其实就是你把它这个new的时候,或者C里边叫lo,或者叫什么东西对吧,在分配内存的时候,把它要分配的那个空间的大小当成参数传进来,这就相当于实现了一个动态的大小的数字,但是这个一旦给定,那这个B的长度大家说是不是。
20:45
固定的,对,这个时候就已经固定了,你即使再改这个LA,其实B的大小也是固定的,已经放在这儿了,对吧,所以大家就可以看到啊,那后面就有两句assert assert大家前面给大家提过一句,Asser跟require不一样,就是assert是表示你这个是一定是对的,如果这个不对的话,就我程序出bug了,出问题了。
21:09
所以大家可以看到,Aser a.length一定是等于七的b.length一定是等于length。所以大家可以跑一下这个这个程序,我我们来实现一下吧,大家还是得手敲啊,光这么看确实是看的不是很很清楚,好,我们在这里还是实现一个function,刚才它叫什么名字,呃,无所谓了啊,这个名字肯定无所谓了,我们这个叫function吧,比方说叫for,然后我们传进来一个UN烂对吧,一个长度public q,然后我们这里可以就是为了看它的一些东西,我们可以定义一些返值啊,比方说我们先定义一个u int类型的返回值,然后我们在里边先定义一个u int类型的数组,大家注意我们还给了一个memory类型是吧,现在我们先先就是大家先熟悉熟悉这种写法,等一下我们详细讲一下。
22:17
这个library啊,Memory一个等于new,呃,应该是大家看这里我们给定一个十吧,我们给它分配十个空间,好,我们先来看一下,假如这个时候大家说我现在去return的话。我可以直接A吗?啊,这会儿肯定不行啊,就是因为我们这里是没有这么定义啊,假如我这么定义的话,可以吗?其实是可以的啊,就是当然这个是应该要求版本,应该有要求,我我忘记具体的版本了,就是编译器应该是得在版本比较高的编译器里面才能支持这种,就是返回一个动态类型,动态长度的数组才才允许这样的返回啊。
23:12
好,我们现在看一下它会返回一个什么东西,大家大家说这个会返回什么东西。放放放,放在这里。大家可以看到全是零对吧?对很多同学都已经想到了,因为这是扫里边的一个特点,就假如说我们没有初始化赋值的话,那它默认的初值全是零,所以我们给了一个这样的A,然后给它分配了十个空间,分配了十个就是U的空间的这个存储空间,那然后我们没有给它赋值,那它肯定就全是零,然后我们直接返回,大家看到就是十个零。UNIT256,好,那么我们再来看一下,我们还可以定义BY是吧,那我们BEST32吧,321个memory。
24:10
啊三二这就已经定长了是吧,我们不要定长BY啊,直接BA,那就是表示它是一个动态长度,长度可变的一个字符数组,一个b new好,我们后边跟一个跟一个大小叫LA好。这个时候我们还是返回一下啊,我们把这个来做一个返回好。做一个deploy,大家猜这个B里面应该是什么?大家看直接就有一个0X,这是为什么呢?为什么呢,因为我们就没有给烂对不对。
25:02
所以如果我们没有给LA,那它这里面默认是不是LA也是零,所以相当于B只是定义了一个变量,但是没有给它分配存储空间,所以大家可以看到它里边其实什么东西都没有,它只是有一个就是0X,这其实是默认的一个头嘛。所以说它只有这个,呃,默认的一个头,然后里面没有东西,好,那我们给他一个一试试啊,诶大家看给了一之后,为什么返回是0X00呢。因为给了一,所以LA就是一,B就有了一个长度,对吧,所以它就包含一个BY。一个BA是几位,一个BAT是几位,八位对,那我们这里显示的是16进制对吧?所以两个零是不是就是八位,也就是我们二进制的八个零,所以说它显示0X00,那大家是不是能推测出来,我这里要给二呢?
26:13
应该是什么?对大家能想到了对吧,给二当然就是0X0000就是16位对吧,就是两个base,所以大家可以看到这个过程当中,它是它是怎么样一个东西。
我来说两句