00:00
接下来我们就继续讲这个跟数组相关的这个话题,刚才大家其实已经看到了,在这个memory类型里边,其实它是就是我们考虑平常在考虑内存分配的时候,这已经涉到涉及到比较底层的一些东西了,就是内存管理,其实这是大家在写程序的时候,呃,就是进阶版的一个技能,就是要考虑到我们内存的分配和管理。接下来我们再简单的看一下结构体,结构体的话,那这个这个我们可以说的简单一点啊,因为它跟C,大家一看这个结构非常的像,我们这里就把那个我们ball里边的这个简单的提了几项出来,大家看就跟C一样,对吧,Structure,然后里边you int定义一个weight,布尔,布尔型的变量定义一个voted,然后又定义一个vote。所以我们看所有的,呃,就是在这个一个结构体里边,我们可以自定义。
01:04
所有的别的基本类型作为它的成员,那大家可以注意,就是说本身结构体structure是可以用在映射和数组里边的,比如说我们可以定义一个数组是一个结构体的数组,比方说这里的voter,我们可以定义一个数组是vote,后面跟方括号,那它就是vote类型的数组。另外就是它本身也可以就是用在映射里面。而且大家注意啊,它可以作为映射和数组的元素,同时它本身里边的元素也可以包含映射和数组,所以以后大家看稍微复杂一些的合约的时候,就会发现,在这个比方说一个这样的一个结构体里边,它还会再定义比方说U,一个方括号数。还会再定义一个mapping。所以,所以大家可以看到,就是扫地里边所有这几种引用类型,它们互相之间是可以有包含关系的,而且用法非常灵活。呃,最后有一个需要强调的是结构体啊,不能包含自己类型的成员,这个在有一些语言的语法里边可能是允许的,就是比方说我这里定义了一个ru voter里边我自己又包含了一个voter类型。
02:25
有些语言可以对吧,但是里言不可以,就是它是不允许,就是变成这种引用引用循环的这种这种样式,所以大家注意一下这一点就可以啊,但是就是它可以作为自己数组类型的成员,数数数组成员的数据类型,也就是说我尽管。呃,就是不能包含一个voter类型的成员,但是可以包含。Water的数组,对,它这个很奇怪啊,大家可以看到这是为什么呢?其实就是因为数组的这样的数据类型,它是一个引用类型,在实际的存储空间里面表示的时候,其实不是把它全部的元素都存到这个存储空间的,它的元素是另外哈希出去存储的,所以在这个时候我们就可以相当于只把它的头放在这里面,那这个就是固定的,可以包含进来的。
03:27
但是如果说自己要包含自己的话。这样就会有有问题,就是这个循环引用的这样的一个状态,好这个就不多说了,我们主要还是看后面这个mapping mapping可能会稍微复杂一点,那我们看它的标准的声明的格式,就是mapping关键字后面一个括号。括号前面是一个它的K的type,就是直键的类型,然后后面一个就像箭头一样,大家如果写JS用那个呃,ES6ES7的语法箭头函数的话,就发现跟这个一样,对吧?当然这个不是箭头函数,它就是表示mapping的映射关系,从P到value的映射关系,呃,那定义的时候呢,我们就得把K和value的数据类型全定义好,这里写的是数据类型,我们其实在前面的这个投票和子货币的合约里边都已经见到了卖品类型啊,呃,那么这个这里是要给大家再强调一些理论,就是剑的类型可以是任何的基本类型。
04:35
这就意味着我们前面讲过的直类型,所有的那些布尔型,整形,浮点型,呃,结构体什么那个,呃结构体不是纸类型啊,就是包括枚举类型,所有的这些都可以,然后还要再加上。就是我们的变变长字字节,这个应该写错了啊,应该就是字符数组和字符数组和字符字符串,我把这改一下,他的key大家要注意,允许的是任何的基本类型,但是不允许是哦,刚才我说错了,我把把枚举也加上了,没有枚举类型啊,就是它的品键值键的这个类型,不能是枚举mapping,还有我们的ru。
05:34
还有就是除了前面的这个BY和string之外的任何数组类型。也就是说,复杂的这些结构都不能当P。啊,这个大家其实也可以直观的可以可以想到,对吧,你要建一个映射嘛,你你从一个整整形,然后映射到另外一个地方,有些同学不是说它有点像字典嘛,但你说字典的时候,你肯定是用一个简单的类型映射到一个复杂的类型,我们有这种用法,是拿一个很复杂的东西去映射一个东西吗?那你查的时候怎么查啊,呃,所以它是限制了这样的一个做法,事实上它的存储空间里面做不到,就是不能把这些东西当成它的mapping的P,那至于它的value呢,就是它的值,类型呢,那就好说了,可以是任何类型,包括也可以是一个映射,所以之前其实我们在呃投票的合约里边是见到了一个类似的。
06:34
Mapping的对吧,就是一个mapping里边,它的值是一个地址,然后呃,一个mapping里边,首先它的key键是一个地址,地址对应到的值又是一个mapping,所以大家可以见到它可以是有多重的,这种就是嵌嵌套的这种定义的mapping里面还有mapping mapping里面还有mapping。
07:01
呃,那我们再看一个一个例子啊,大家看到这里就是一个映射的。一个事例,我们可以看到,上面定义了两个合约。这里面还有合约的调用啊,我们都可以简单的看一下,上边的这个合约叫做mapping example,那他上来就先定义了一个map类型的状态变量。它的类型从什么到什么呢?就是见键值是什么类型呢?见是address地址类型到一个整形。它定义的这个叫balances啊,所以那其实这个我们不陌生嘛,这不就是我们在定义货币的时候的那个东西嘛,Balances对,然后function它有定义了一个update update会传进来一个整形的new balance。也就是说它定义了一个方法,我们可以自己去改自己的余额,那怎么改呢?改的方法就是我们balances里边它的master send,找出对应的这个地址,它对应的余额给定为new balance。
08:08
就是这么一个方法,所以大家可以想到我直接调这个update方法的话,那就可以传进去一个数,我自己的余额就变了,就变成这个了,对吧,那我们看一下下面怎么怎么样去从外部去调用这个东西啊,那下面就又来了一个定义了一个合约叫做mapping user。我们怎么样去用这个这里的这个。就是余额的这个映射表呢,我们看一下它定义了一个方式,然后它会返回一个u int整形值。首先他先定义了一个mapping example类型的变量,大家可以看啊。合约类型这个我前面没有列出来,合约本身也可以是一个数据类型。所以这就像我们的那个类的定义一样,对吧?这就像定义一个类,所以大家熟悉变对象编程的话,这个都不难,Map example定义一个这样类型的变量,定义一个M,那么它要付出值,它的初始值是怎么办?怎么样去初始化呢?New,一个map example括号,那大家可以知道这个就肯定调用它的constructor了,对吧?那它这里边就没有定义constructor,那肯定就是constructor,什么参数也没有,也是空的,没有什么动作,所以呃,但是它肯定会把它的状态变量要去设定好,对吧?就这些的存储空间是分配好的,那接下来大家看调用的时候调用另外一个合约怎么调用。
09:35
m.update大家看,这就属于从一个合约外边去调用这个合约的方法,就用定义好的这个合约的实例名称M,然后点一个update里边传递参数100,那大家说这个相当于是把谁的balance给改了,余额给改了。
10:05
把谁的余额给改了?他这个调用这是给谁了。好,那我们还是来实际的操作一下吧,好,我们也学它啊,我们在这里这个东西有点多了啊,我们另外建立建一个,我们就用这个test contract吧,这里的删掉,好,假如说我们这个就叫contract c,我们简单一点啊,就叫一个C,呃,然后他一开始做了什么,我们看一下啊,哦,它是在这个mapping example里面去定义了一个这个balance,这个mapping,然后去定义了一个update的方法是吧,好,我们也来学一下这个简单啊,Mapping dress类型到you的一个映射,这个叫balances,好,然后我们定义一个function,这个叫update update里边会去传一个amount,对吧,要给它变成的数字变成多少,它是。
11:19
一个public类型的函数,然后接下来我们就是直接把它改了,怎么改呢?呃,那就是直接在balances里边找到message点那。它对应的这个数字就是它的余额对吧,那我们直接等于amount,好,这个就把它改完了,那这个合约我们已经完了啊,然后我们再再定义一个合约,然后我们就叫D,就简单一点CD。呃,然后我们这里边就要调用这个这个方法,我看它是怎么调用的来着。
12:02
啊,拗了一个这个合约的实例对吧,然后去去用它去调用,好我们就这么来用一下啊方式,呃随便用一个,呃不不能写号啊,我们随便定一个,这就是叫名字放吧,这个也是一个public类型,好接下来我们在里边就要定义一个C差类型对吧。那我们定义一个自己的contract,我们不要就叫靠,不要跟他的那个关键词重合啊,New一个C,然后这就有了这样的一个合约对象对吧?然后我们就可以调用这个对象里面的方法c.UPDATE10对吧,好,它为了方便应该是还定义了返回值的,对吧,Returns一个。
13:00
好,那接下来我们就让他直接返回大家,大家现在猜不出来他是他是这个update了谁对吧,那我们就返回一个东西来看一下我们大家想返回谁的。想返回C的吗?就是这个就是我们的com contract这个自己定义的,这个我们直接定义C好了啊看这说着也难受,好那我们就好就来看一看吧C,那我们要拿他的余额怎么去拿。Address address括号C,然后呢,点点balance。那个余额是他的以太余额对吧,这个咱们现在改的这个是以太以太余额吗。
14:03
如果要这么简单的话,那就简单了,对吧,我自己布个合约上去,我把自己的数一改就改了,这个是相当于这个balance,对,注意对对对,咱们现在是要拿这个自己自定义的这个balance就相当于一个子货币,对吧,这样子的话,是不是应该要哪个要个说上面的这个要public是吧?呃,如果要是说对,咱们这里如果要是没有把它定义public的话,那确实是访问不到对吧?对,那如果说我们想让它访问的话,那这里还应该再定义一个对方式get balance。对吧,Address我们就随便定义一个这个吧,这个要定义成public,别人就可以访问他的私有变量了,好,我们看一下这里就是这个要有一个return的啊returns。
15:15
我们这里直接特什么。我们是不是应该对应该在balances里面找对吧,对,就是要return一个,那找谁的呢?那肯定就是找谁的,我们就找他传谁的,我们就找谁的对吧,对,所以其实就是这样啊,所以那我们这里边就可以怎么样呢?我们可以怎么样c.get balance对吧。Get balance是什么?呃,大家大家想看谁的吧?那我们就就看一下address c好了,对吧?如果大家想看C的,我们就看一下C,诶,这里报错了,我看一下啊。
16:08
哦,大家看这个。我们这啊,这个returns写太蠢了,好,我们来部署一下。好,现在我们部署完了之后,大家会发现我们这里。先部署了一个C啊,我们还得部署一个D,对吧。其实我们不需要C,因为C是会在D里边会去他自己去创建这个实例的,对吧,其实我们不需要部署C啊。好,我们看这里边有一个放,那么大家可以看一下。大家可以看一下,这里已经调用成功了,但是我们怎么查这个东西呢?这好像我们有点问题是吧,这个查不到。
17:09
所以在这个过程当中,其实如果我们要查的话,其实我们还得知道,就是这里创建出来的C的这个合约地址才行,才能在上面去查,因为我们上面的这个C其实跟这里是不一样的,对吧?对,其实跟这里是不一样的,所以在这里我们的这种返回其实是就是是会有问题的,我们去这样去查查C的,但是我们可以去,我们我们可以去查自己是不是我们看一下本来的这一个应该是会返回。到address this对吧,诶他这里应该是定义成public了吧,我们看一下哦,果然它上面是直接把这个定义成public了,我们学一下太好了。
18:00
把上面如果定义成public,那我们是不是就可以直接用c.balance了,对吧,就是刚才刚才有同学说到的,就是上面如果不是public,你没没办法访问,那我们这里的话,好,那我们这个这个就不需要了,Return它的balances c.balances。那对应的这个地址给什么呢?我们可以给,就是查当前对吧,给一个address this可以给一个这样的东西,嗯,哪里又有问题。呃。In depth expression has To Be a type。Mapping on a ray,所以他说的是这里边的东西一定要是。他的一个。
19:02
就一定要是它的一个,就是索引的一个表达式。所以大家可以看到,哎,这个里边我我们跟这里面是什么东西写的不一样吗?哎,大家大家想一想,这里是哪里有问题了,为什么他会报这么一个错,我们这么访问不对吗。这里给大家多说一句啊,就是我们如果要是说定义了C之后,去访问它的C的balances这个变量,其实不是去直接访问的这个变量。如果我们认为这就是这个变量的话,我们肯定就在后边直接放括号就可以取它了,对吧?对,我们这里访问的其实是内置的那个方法,大家还记得吗?我们如果要是定义了这样的一个public类型的话,相当于我们定义了一个function,叫做balances的一个function,对吧?对,我们相当于是定义了一个这个东西。
20:10
那大家注意mapping类型的变量,如果是定义了public的话,它的function里边是可以传入它的这个索引值,就是它的这个键,然后去查询它内部的就是真正的value,所以我们这里可以我们不能传这个,但是可以去给他传,就是调用它的这个方法,我们在这里不能直接访问这个数组,但是可以调用它的方法,那所以大家就可以以看到。在这个我们的合约里边,哎呀,这怎么写,在我们的合约里边,可以写成这个形式,所以是这样的一个用法,好,那我们现在再布一下。Deploy这个地看一下。
21:05
还是没有返回啊,看一下哦,大家可以看到它这个很奇怪,没有在这里直接显示出来啊,但其实是在这里是有的,对吧。来看一下它的output。就是在这里是返回了一个UNIT256的十的,这可能是这个就是remix的一个一个问题啊,他既然拿到这个返回值,它是完全完全可以写在这,因为他把那个11点的时候,其实你这边只要把那个,因为你觉得是吗?因为你在你看你那个第四行面方法,这个方法对你的肯定就是那你觉得我这里可以的是吗。
22:06
好,咱们试一下啊S第二这样是吧,好,我们来部署一下。我们把上面这个删掉啊,诶全删了。D。好部署。现在有一个方式,我们为了看清楚,我们把它全删了啊好,我们看一下这个返回的是什么零,为什么呢。这里的是谁?是D吗?D里边的点三角是谁?呃,大家要搞清楚这个调用的调用的关系啊,这个D的合约是我们来调用的对不对,C的合约是D来调用的对不对?所以C里边的mes center,他只要没有用代理,就我们所说的那个委托调用,代理调用,那一定就是D,对吧?所以我们查这里边的这个查出来是事实,但是如果我们在D里边用message send的话,这个应该是我这里的这个地址对不对?
23:30
你能想到是吧。对,所以说如果要是这样的话,我们查的其实是我这个地址里边的balances,所以当然就是零了。对吧,这两个不一样,所以我们这里看到这个十刚才update到底update谁,因为update就是D。对吧,就是D,所以我们如果要是查的是D的话,才可以查出来,如果大家查C的地址的话,因为C的地址其实我们这里获取不到,主要是对吧,那我们如果要是在这里的话,想要去获取地址,我们直接在这里去传一个,我们可以试一下啊,看一下它会不会有一个东西出来。
24:16
Deploy,诶,在下面。大家看这个连东西都没有。所以就是说在这个里边,他去获取C的地址,然后去调用这个方法的时候,会发现这个东西是没有东西的。那如果说我们这里去传一个。别的地址的话,大家会发现,因为我们没有更新过它的余额,所以说它的余额肯定都是零。而我们如果要是。在这里。哎,你不是第12行update的时候,是因为你是D调用了这个c update,然后你这个时候的不是应该等于一个,嗯,你说这里的这个,咱们刚才把这个改成12号,嗯,12号候这时候这个了,不是应该等于地了。
25:20
对,就是因为C调用了C,所以C里边的message center就是D,对不对对啊,所以咱们查D的余额的时候,发现这刚才这个UPDATE10UPDATE的D。查D的balance查出来是十对吧?咱们这里的address this,这是D吗?所以如果这样去查的话,查出来是十。如果查别人的话就不行,而且这里D的地址不是就是刚才咱们说的me send对吧,这两个me send不是一回事。这就是大家一定搞清楚,就是我们所说的那个到底是谁发起的消息,谁是master,我们我们在这里去调用D的方法,我们自己的地址是message message send d在自己的方法里面去调C,那在C这里D是他的message send。
26:18
倒一下这个这个关系应该能倒的清是吧。
我来说两句