代码改变世界

02 基础篇 —引用类型

2019-12-02 14:19  StevenZhao  阅读(156)  评论(0编辑  收藏  举报

2 引用类型

不定长字节数组(bytes)

-动态字节数组

-引用类型(表明可以使用 storage 来修饰,进行引用传递,指针的效果) -支持 下标索引 -支持 length 、 push 方法(push会帮助分配空间的) -可以修改 -以十六进制格式赋值: 'h' -> 0x68 -> 104 -格外注意:对于bytes,如果不使用下标访问,那么可以不用先申请空间, 直接赋值即可,或者 直接push

代码:

 1 pragma solidity ^0.4.24 ;
 2  3 contract Test{
 4 //动态字节数组,使用new关键字,分配空间
 5 bytes public name=new bytes(32);
 6 bytes public name1;
 7 function setLength(uint _length)public {
 8     name.length=_length;
 9 }
10 11 function getLength(bytes _name)public pure returns(uint){
12     return _name.length;
13 }
14    function setName(bytes _name)public {
15        name=_name;
16        
17    } 
18    function changeName(bytes1 _name)public{
19        name[0]=_name;
20    }
21       /*
22     function changeName1(bytes1 _name)public{
23         //为未分配空间,访问下表下标错误
24         name1[0]=_name;
25     }
26     */
27 function pushTest()public{
28     name1.push("a");
29 }
30 function setInside()public{
31     name="hello";
32     name1="hello world";
33 }

 

 

字符串(string)

-动态尺寸的UTF-8编码字符串,是特殊的可变字节数组 -引用类型 -不支持下标索引 -不支持length、push方法 -可以修改(需通过bytes转换)

-使用下标索引的话,转成bytes类型

代码:

 1 pragma solidity ^0.4.24;
 2 contract String{
 3     //引⽤用类型;不支持下标索引;不支持length、push⽅方法;可以修改(需通过bytes转换)
 4     //下表x索引,length都转换成不用bytes来操作
 5     string public name="steven";
 6     function nameBytes()constant returns(bytes){
 7         return bytes(name);
 8     }
 9     function nameLength()constant returns(uint){
10        //return name.lengh; //z不支持直接使用
11        return bytes(name).length;
12     }
13     function changeName()public{
14     name="mark";
15  // name[1}="l";不支持直接索引
16  bytes(name)[0]="l";
17 18 }
19    function changeLength()public{
20        bytes(name).length=10;
21    }
22      

 

 

数据位置(Data location)

复杂类型,不同于之前 值类型 ,占的空间更大,超过256字节,因为拷贝它们占用更多的空间,如数组(arrays) 和 数据结构(struct) ,他们在Solidity中有一个额外的属性,即数据的存储位置: memory 和 storage 。

​ - 内存(memory)

数据不是永久存在的,存放在内存中,越过作用域后无法访问,等待被回收; 被memory修饰的变量是直接拷贝,即与上述的值类型传递方式相同。

-存储 (storage)

数据永久保存在。 被storage修饰的变量是引用传递,相当于只传地址,新旧两个变量指向同一片内存空间,效率较高,两个变量有关联,修改一个,另外一个同样被修改; 只有引用类型的变量才可以显示的声明为 storage 。

  • 状态变量量

状态变量总是stroage类型的,无法更改;

  • 局部变量量

默认是storage类型(仅限数据结构或数组,string),但是可以声明为memory类型。

-对于非值的数据类型,比如数组和结构体,赋值的语法比较复杂:

.赋值给一个状态变量总是创建一个完全无关的拷贝

.赋值给一个局部变量,仅对基本类型,如那些32字节以内的(静态类型(static types)),创建一份完全无关的拷贝;

.如果是数据结构或数组,(包括bytes和string)类型,由状态变量赋值为一个局部变量,局部变量只是持有原始状态变量的一个引用。对于这个局部变量再次赋值,并不会修改这个状态变量,只是修改了引用(局部变量指向了别人);但是修改这个本地引用变量(局部变量)的成员值,会改变状态变量的值(修改了所引用的状态变量值)localTest()的测试

代码:

 

 1 pragma solidity ^0.4.24;
 2  3 contract test2{
 4    //memory:存放在内存中,不是永久存在,超越于作用域后,等待被回收;志值传递
 5     //storage:数据永久保存,引用传递传递,c效率高
 6     //状态变量变量总是storage类型;局部变量是storage(仅限数据结构或数组,string),但是可以memory
 7 string public name= 'lily';
 8 uint256 public num = 10;
 9 10 function call1() public {
11     setName1(name);
12 }
13 //对于引用数据类型,作为函数参数时 默认是memory类型(值传递)
14 function setName1(string src) private {
15 //function setName1(string memory src) private {
16     num = 100; //num变为100
17     bytes(src)[0] = "L";//name还是小写
18 }
19 function call2() public {
20     setName2(name);
21 }
22     
23 //如果想引用传递,需要显示指明storage
24 function setName2(string storage src) private {
25         num = 1000;//num为1000
26         bytes(src)[0] = "L";//name变成大写
27     }
28     
29 //如果局部变量是string,数组,结构体类型数据,默认是storage类型    
30  function localTest () public {
31     string memory tmp = name;
32     bytes(tmp)[0] = "L";//name变大写
33 } 
34
View Code

 

转换(byte1/bytes/string)

 1 pragma solidity ^0.4.24;
 2 contract Transformation{
 3     //(byte1/bytes/string)相互转换
 4     
 5      bytes10 b10 = 0x68656c6c6f776f726c64;     //helloworld
 6     //bytes bs10 = b10; //⽆无法直接转换
 7     
 8   
 9     bytes public bs10 = new bytes(b10.length);
10     
11     //1. 固定字节数组转动态字节数组;需要逐一赋值
12     function fixedBytesToBytes() public{
13         for (uint i = 0; i< b10.length; i++){
14             bs10[i] = b10[i];
15         }
16     }
17     //2.string转动态字节数组
18     string  greeting = "helloworld";
19     bytes public b1;
20     function StringToBytes() public {
21         b1 = bytes(greeting);
22     }
23     //3. 动态字节数组转string
24     string public str3;
25     function BytesToString() public {
26         fixedBytesToBytes();
27         str3 = string(bs10);
28     }
29      function FiexBytesToString(){
30      //固定字节数组和string无法转换
31         //string tmp = string(b10);
32     }
33     
34 }
View Code

 

数组

-内置数组:string(不定长)、bytes(不定长)、byte1,byte2...(定长);

-自定义数组:

类型T,长度K的数组定义为T[K],例如:uint [5] numbers, byte [10] names; 内容可变; 长度不可变,不支持push; 支持length方法。

-不定长数组:

定义格式为T [ ],例例如:string[ ] names, byte[ ] citys; 内容可以修改; 可以改变长度(仅限storage类型) 支持 length 、 push 方法; memory类型的不定长数组不支持修改长度;

 1 pragma solidity ^0.4.24;
 2 contract C {
 3     /*
 4     定长数组
 5     */
 6      uint[10] value = [1,2,3,4,5];
 7      uint public sum;
 8      
 9     function getSum()public returns(uint ){
10        sum=0;
11         for (uint i = 0; i < value.length; i++){
12             sum += value[i];
13             
14         } 
15         return sum ;
16     }
17     function changeValue(){
18         value[0] = 2; //内容可修改
19         //value.length = 100; //报错,长度不可修改
20     }    
21     
22     //test2:
23     //helloworld : 0x68656c6c6f776f726c64
24     bytes10 helloworldFixed = 0x68656c6c6f776f726c64;
25     byte [10] helloworldDynamic = [byte(0x68), 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64];
26     bytes helloworld;
27     
28     function changeByte() public {
29         //helloworldFixed[0] = 0x69; //error
30         helloworldDynamic[0] = 0x69; //ok
31     }
32     
33   function getString () public constant returns (string) {
34     for (var i = 0; i < helloworldDynamic.length; i++) {
35      helloworld.push(helloworldDynamic[i]);//不定长字节数组,没有开辟空间,可以直接赋值或者push 
36         }
37         
38         return string(helloworld);
39     }
40
View Code

 

结构体

 1 pragma solidity ^0.4.24;
 2 contract StructType{
 3      //定义结构之后无分号,与枚举⼀致
 4     struct Student{
 5         string name;
 6         uint age;
 7         uint score;
 8         string sex;
 9     }
10     Student []public Students;//定义结构体数组
11     //看两种赋值方式
12     Student public stu1=Student("steven",18,99,"m");
13     Student public stu2=Student({name:"mark",age:19,score:90,sex:"w"});
14     function assign()public{
15         Students.push(stu1);
16         Students.push(stu2);
17         stu1.name="lily";
18     
19     }
20 }

 

字典/映射/哈希(mapping)

-键key的类型允许除映射外的所有类型,如数组,合约,枚举,结构体,值的类型无限制; -无法判断一个mapping中是否包含某个key,因为它认为每一个都存在,不存在的返回0或false; -映射可以被视作为一个哈希表,在映射表中,不存储键的数据,仅存储它的 keccak256 哈希值,用来查找值时使用; -映射类型,仅能用来定义状态变量,或者是在内部函数中作为storage类型的引用。 -不支持length -key不支持string 类型​

 1 pragma solidity ^0.4.24;
 2  3 contract test{
 4     //id->name
 5     mapping(uint=>string)id_name;
 6     constructor ()public{
 7         //构造函数
 8         id_name[0x01]="steven";
 9         id_name[0x02]="lily";
10         id_name[0x03]="mark";
11 }
12 function getNameById(uint id)public view returns(string){
13     string memory name=id_name[id];
14     return name;
15     }
16 }

 

引用类型之间的比较