从零构建以太坊(Ethereum)智能合约到项目实战——学习笔记8
P35 、Solidity Types - 字符串(String Literals)
Solidity中的string字符串不像C语言一样以\0结束。
pragma solidity ^0.4.4; contract StringLiterals{ string _name;//状态变量 //构造函数 function StringLiterals(){ _name = "this is a girl!"; } function setName(string name){ _name = name; } function name() constant returns(string){ return _name; } }
备注:string字符串不能通过length方法获取其长度。
P36 、1-固定大小字节数组(Fixed-size byte arrays) bytes1 ~P 、 bytes32
固定大小字节数组(Fixed-size byte arrays)
固定大小字节数组可以通过bytes1,bytes2,bytes3,....,bytes32来进行声明。PS:byte的别名就是byte1。
- bytes1只能存储一个字节,也就是二进制8位的内容。
- bytes2只能存储两个字节,也就是二进制16位的内容。
- bytes3只能存储三个字节,也就是二进制24位的内容。
- ........
- bytes32只能存储三十二个字节,也就是二进制256位的内容。
pragma solidity ^0.4.4; contract C{ byte public a = 0x6c; bytes1 public b = 0x6c; bytes2 public c = 0x6c69; bytes3 public d = 0x6c6979; bytes4 public e = 0x6c697975; }
P37 、2-Solidity Types - 固定大小字节数组(Fixed-size byte arrays) - 比较运算符
操作运算符
- 比较运算符:<=、<、==、!=、>=、>
- 位运算符:&、|、^(异或)、~(取反)、<<(左移)、>>(右移)
- 索引访问:如果x是一个bytesI,那么可以通过X[k](0<k<I)获取对应索引的字节,PS:X[k]是只读,不可写。
pragma solidity ^0.4.4; contract C{ bytes1 b10 = 0x6c; // l bytes2 b11 = 0x69; // i // <=、<、==、!=、>=、> function test1() constant returns(bool){ return b10<=b11; } function test2() constant returns(bool){ return b10<b11; } function test3() constant returns(bool){ return b10==b11; } function test4() constant returns(bool){ return b10!=b11; } function test5() constant returns(bool){ return b10>=b11; } function test6() constant returns(bool){ return b10>b11; } }
P38 、3-Solidity Types - 固定大小字节数组(Fixed-size byte arrays) - 位操作符
操作运算符
- 比较运算符:<=、<、==、!=、>=、>
- 位运算符:&、|、^(异或)、~(取反)、<<(左移)、>>(右移)
- 索引访问:如果x是一个bytesI,那么可以通过X[k](0<k<I)获取对应索引的字节,PS:X[k]是只读,不可写。
pragma solidity ^0.4.4; contract C{ bytes1 b10 = 0x6c; // l bytes1 b11 = 0x69; // i // &、|、^(异或)、~(取反)、<<(左移)、>>(右移) function test1() constant returns(bytes1){ return b10 & b11; //0110 1100 -> 0x6c //0110 1001 -> 0x69 //0110 1000 -> 0x68 } function test2() constant returns(bytes1){ return b10 | b11; //0110 1100 -> 0x6c //0110 1001 -> 0x69 //0110 1101 -> 0x6d } function test3() constant returns(bytes1){ return ~ b10; //0110 1100 -> 0x6c //1001 0011 -> 0x93 } function test4() constant returns(bytes1){ return b10 << 1; //0110 1100 -> 0x6c //1101 1000 -> 0xd8 } function test5() constant returns(bytes1){ return b10 >> 1; //0110 1100 -> 0x6c //0011 0110 -> 0x36 } }
P39 、4-Solidity Types - 固定大小字节数组(Fixed-size byte arrays) - 索引访问
操作运算符
- 比较运算符:<=、<、==、!=、>=、>
- 位运算符:&、|、^(异或)、~(取反)、<<(左移)、>>(右移)
- 索引访问:如果x是一个bytesI,那么可以通过x[k](0<k<I)获取对应索引的字节,PS:x[k]是只读,不可写。
pragma solidity ^0.4.4; contract C{ bytes9 b9 = 0x6c6979756563687563; function test(uint index) constant returns(byte){ return b9[index]; } }
P40 、5-Solidity Types - 固定大小字节数组(Fixed-size byte arrays) - length
操作运算符
- 比较运算符:<=、<、==、!=、>=、>
- 位运算符:&、|、^(异或)、~(取反)、<<(左移)、>>(右移)
- 索引访问:如果x是一个bytesI,那么可以通过X[k](0<k<I)获取对应索引的字节,PS:X[k]是只读,不可写。
成员函数
- .length返回字节的个数。(只读)
pragma solidity ^0.4.4; contract C{ bytes9 b9 = 0x6c6979756563687563; function test() constant returns(uint){ return b9.length; } }
P41 、6-Solidity Types - 固定大小字节数组(Fixed-size byte arrays) - 不可变深度理解
不可变深度解析
长度不可变
pragma solidity ^0.4.4; contract C{ bytes9 name = 0x6c6979756563687563; function setNameLength(uint length) { //报错 name.length = length; } }
内部字节不可修改
pragma solidity ^0.4.4; contract C{ bytes9 name = 0x6c6979756563687563; function setNameFirstByte(byte b) { //报错 name[0] = b; } }
总结:bytesI (1<= I <= 32)可以声明固定字节大小的字节数组变量,一旦声明,内部的字节和字节数组长度不可修改,当然可以通过索引读取(只读)对应索引的字节,或者通过length读取字节数组的字节数。
P42 、1-Solidity Types - 动态大小字节数组(Dynamically-sized byte array)
一、Dynamically-sized byte array
- string是一个动态尺寸的utf-8编码字符串,它其实是一个特殊的可变字节数组,string是引用类型,而非值类型。
- bytes动态字节数组、引用类型。
根据经验,在我们不确定字节数据大小的情况下,我们可以使用string或者bytes,而如果我们清楚知道或者能够将字节数控制在bytes1~bytes32,那么我们就使用bytes1~bytes32,这样的话能够降低存储成本。
P43 、2-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - string to bytes
二、常规字符串string转换为bytes
string字符串中没有提供length方法获取字符串长度,也没有提供方法修改某个索引的字节码,不过我们可以将string转换为bytes,再调用length方法获取字节长度,当然可以修改某个索引的字节码。
pragma solidity ^0.4.4; contract C{ bytes9 g = 0x6c697975656368756e; string name = "liyuechun"; function gByteLength() constant returns(uint){ return g.length; } function nameBytes() constant returns(bytes){ return bytes(name); } function nameLength() constant returns(uint){ return bytes(name).length; } function setNameFirstByteForL(bytes1 z){ // 0x4c=>"L" bytes(name)[0] = z; } }
P44 、3-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 特殊字符对应的字节数
三、汉字字符串或特殊字符的字符串转换为bytes
1、特殊字符
pragma solidity ^0.4.4; contract C{ string public name = "a!+&520"; function nameBytes() constant returns(bytes){ return bytes(name); } function nameLength() constant returns(uint){ return bytes(name).length; } }
在这个案例中,我们声明了一个name字符串,值为a!+&520,根据nameBytes和nameLength返回的结果中,我们不难看出,不管是字母、数字还是特殊符号,每个字母对应一个byte(字节)。
P45 、4-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 汉字对应的字节数
2、中文字符串
pragma solidity ^0.4.4; contract C{ string public name = "黎跃春"; function nameBytes() constant returns(bytes){ return bytes(name); } function nameLength() constant returns(uint){ return bytes(name).length; } }
在上面的代码中,我们不难看出,黎跃春 转换为bytes以后的内容为0xe9bb8ee8b783e698a5,一共9个字节。也就是一个汉字需要通过3个字节来进行存储。
P46 、5-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 创建bytes字节数组
pragma solidity ^0.4.4; contract C{ bytes public name = new bytes(1); function nameBytes() constant returns(bytes){ return bytes(name); } function setNameLength(uint length){ name.length = length; } function nameLength() constant returns(uint){ return name.length; } }
P47 、6-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 可变字节数组和不可变字节数组深度对比
pragma solidity ^0.4.4; contract C{ bytes public name = new bytes(1); function nameBytes() constant returns(bytes){ return bytes(name); } function setNameLength(uint length){ name.length = length; } function nameLength() constant returns(uint){ return name.length; } function setIndexByte(byte data, uint index){ name[index] = data; } function clearBytes(uint len){ name.length = len; //清空数组 //name.length = 0; //或者delete清空 //delete name; } }
P48 、7-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 可变字节数组中push方法的使用
pragma solidity ^0.4.4; contract C{ //0x6c697975656368756e //初始化一个两个字节空间的字节数组 bytes public name = new bytes(2); function setNameLength(uint length){ name.length = length; } function nameLength() constant returns(uint){ return name.length; } function pushAByte(byte b){ name.push(b); } }
说明:当字节数组的长度只有2时,如果你通过push往里面添加一个字节,那么它的长度将变为3,当字节数组里面有3个字节,但是你通过length方法将其长度修改为2时,字节数组中最后一个字节将被从字节数组中移除。
P49 、8-Solidity Types - 动态大小字节数组(Dynamically-sized byte array) - 小结
对比分析:
- 不可变字节数组
我们之前的文章中提到过如果我们清楚我们存储的字节大小,那么我们可以通过bytes1,bytes2,bytes3,。。。,bytes32来声明字节数组变量,不过通过bytes1来声明的字节数组为不可变字节数组,字节不可修改,字节数组长度不可修改。
- 可变字节数组
我们可以通过bytes name = new bytes(length)-length为字节数组长度,来声明可变大小和修改字节内容的可变字节数组。