2 引用类型
不定长字节数组(bytes)
-动态字节数组
-引用类型(表明可以使用 storage 来修饰,进行引用传递,指针的效果) -支持 下标索引 -支持 length 、 push 方法(push会帮助分配空间的) -可以修改 -以十六进制格式赋值: 'h' -> 0x68 -> 104 -格外注意:对于bytes,如果不使用下标访问,那么可以不用先申请空间, 直接赋值即可,或者 直接push
代码:
pragma solidity ^0.4.24 ;
contract Test{
//动态字节数组,使用new关键字,分配空间
bytes public name=new bytes(32);
bytes public name1;
function setLength(uint _length)public {
name.length=_length;
}
function getLength(bytes _name)public pure returns(uint){
return _name.length;
}
function setName(bytes _name)public {
name=_name;
}
function changeName(bytes1 _name)public{
name[0]=_name;
}
/*
function changeName1(bytes1 _name)public{
//为未分配空间,访问下表下标错误
name1[0]=_name;
}
*/
function pushTest()public{
name1.push("a");
}
function setInside()public{
name="hello";
name1="hello world";
}
字符串(string)
-动态尺寸的UTF-8编码字符串,是特殊的可变字节数组 -引用类型 -不支持下标索引 -不支持length、push方法 -可以修改(需通过bytes转换)
-使用下标索引的话,转成bytes类型
代码:
pragma solidity ^0.4.24;
contract String{
//引⽤用类型;不支持下标索引;不支持length、push⽅方法;可以修改(需通过bytes转换)
//下表x索引,length都转换成不用bytes来操作
string public name="steven";
function nameBytes()constant returns(bytes){
return bytes(name);
}
function nameLength()constant returns(uint){
//return name.lengh; //z不支持直接使用
return bytes(name).length;
}
function changeName()public{
name="mark";
// name[1}="l";不支持直接索引
bytes(name)[0]="l";
}
function changeLength()public{
bytes(name).length=10;
}
数据位置(Data location)
复杂类型,不同于之前 值类型 ,占的空间更大,超过256字节,因为拷贝它们占用更多的空间,如数组(arrays) 和 数据结构(struct) ,他们在Solidity中有一个额外的属性,即数据的存储位置: memory 和 storage 。
- 内存(memory)
数据不是永久存在的,存放在内存中,越过作用域后无法访问,等待被回收; 被memory修饰的变量是直接拷贝,即与上述的值类型传递方式相同。
-存储 (storage)
数据永久保存在。 被storage修饰的变量是引用传递,相当于只传地址,新旧两个变量指向同一片内存空间,效率较高,两个变量有关联,修改一个,另外一个同样被修改; 只有引用类型的变量才可以显示的声明为 storage 。
状态变量量
状态变量总是stroage类型的,无法更改;
局部变量量
默认是storage类型(仅限数据结构或数组,string),但是可以声明为memory类型。
-对于非值的数据类型,比如数组和结构体,赋值的语法比较复杂:
.赋值给一个状态变量总是创建一个完全无关的拷贝;
.赋值给一个局部变量,仅对基本类型,如那些32字节以内的(静态类型(static types)),创建一份完全无关的拷贝;
.如果是数据结构或数组,(包括bytes和string)类型,由状态变量赋值为一个局部变量,局部变量只是持有原始状态变量的一个引用。对于这个局部变量再次赋值,并不会修改这个状态变量,只是修改了引用(局部变量指向了别人);但是修改这个本地引用变量(局部变量)的成员值,会改变状态变量的值(修改了所引用的状态变量值)localTest()的测试。
代码:
pragma solidity ^0.4.24;
contract test2{
//memory:存放在内存中,不是永久存在,超越于作用域后,等待被回收;志值传递
//storage:数据永久保存,引用传递传递,c效率高
//状态变量变量总是storage类型;局部变量是storage(仅限数据结构或数组,string),但是可以memory
string public name= 'lily';
uint256 public num = 10;
function call1() public {
setName1(name);
}
//对于引用数据类型,作为函数参数时 默认是memory类型(值传递)
function setName1(string src) private {
//function setName1(string memory src) private {
num = 100; //num变为100
bytes(src)[0] = "L";//name还是小写
}
function call2() public {
setName2(name);
}
//如果想引用传递,需要显示指明storage
function setName2(string storage src) private {
num = 1000;//num为1000
bytes(src)[0] = "L";//name变成大写
}
//如果局部变量是string,数组,结构体类型数据,默认是storage类型
function localTest () public {
string memory tmp = name;
bytes(tmp)[0] = "L";//name变大写
}
转换(byte1/bytes/string)
pragma solidity ^0.4.24;
contract Transformation{
//(byte1/bytes/string)相互转换
bytes10 b10 = 0x68656c6c6f776f726c64; //helloworld
//bytes bs10 = b10; //⽆无法直接转换
bytes public bs10 = new bytes(b10.length);
//1. 固定字节数组转动态字节数组;需要逐一赋值
function fixedBytesToBytes() public{
for (uint i = 0; i< b10.length; i++){
bs10[i] = b10[i];
}
}
//2.string转动态字节数组
string greeting = "helloworld";
bytes public b1;
function StringToBytes() public {
b1 = bytes(greeting);
}
//3. 动态字节数组转string
string public str3;
function BytesToString() public {
fixedBytesToBytes();
str3 = string(bs10);
}
function FiexBytesToString(){
//固定字节数组和string无法转换
//string tmp = string(b10);
}
}
数组
-内置数组: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类型的不定长数组不支持修改长度;
pragma solidity ^0.4.24;
contract C {
/*
定长数组
*/
uint[10] value = [1,2,3,4,5];
uint public sum;
function getSum()public returns(uint ){
sum=0;
for (uint i = 0; i < value.length; i++){
sum += value[i];
}
return sum ;
}
function changeValue(){
value[0] = 2; //内容可修改
//value.length = 100; //报错,长度不可修改
}
//test2:
//helloworld : 0x68656c6c6f776f726c64
bytes10 helloworldFixed = 0x68656c6c6f776f726c64;
byte [10] helloworldDynamic = [byte(0x68), 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64];
bytes helloworld;
function changeByte() public {
//helloworldFixed[0] = 0x69; //error
helloworldDynamic[0] = 0x69; //ok
}
function getString () public constant returns (string) {
for (var i = 0; i < helloworldDynamic.length; i++) {
helloworld.push(helloworldDynamic[i]);//不定长字节数组,没有开辟空间,可以直接赋值或者push
}
return string(helloworld);
}
结构体
pragma solidity ^0.4.24;
contract StructType{
//定义结构之后无分号,与枚举⼀致
struct Student{
string name;
uint age;
uint score;
string sex;
}
Student []public Students;//定义结构体数组
//看两种赋值方式
Student public stu1=Student("steven",18,99,"m");
Student public stu2=Student({name:"mark",age:19,score:90,sex:"w"});
function assign()public{
Students.push(stu1);
Students.push(stu2);
stu1.name="lily";
}
}
字典/映射/哈希(mapping)
-键key的类型允许除映射外的所有类型,如数组,合约,枚举,结构体,值的类型无限制; -无法判断一个mapping中是否包含某个key,因为它认为每一个都存在,不存在的返回0或false; -映射可以被视作为一个哈希表,在映射表中,不存储键的数据,仅存储它的 keccak256 哈希值,用来查找值时使用; -映射类型,仅能用来定义状态变量,或者是在内部函数中作为storage类型的引用。 -不支持length -key不支持string 类型
pragma solidity ^0.4.24;
contract test{
//id->name
mapping(uint=>string)id_name;
constructor ()public{
//构造函数
id_name[0x01]="steven";
id_name[0x02]="lily";
id_name[0x03]="mark";
}
function getNameById(uint id)public view returns(string){
string memory name=id_name[id];
return name;
}
}
引用类型之间的比较