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
转换(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 }
数组
-内置数组: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
结构体
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 }
引用类型之间的比较