1、整型(int)
2、地址类型(address)
3、枚举类型(enum)
4、结构体(struct)
5、映射(mapping)
6、数组(array)
7、字符串和字节数组(string、bytes)
值类型:布尔类型(bool)、整型(int)、地址类型(address)、定长字节数组(bytes)、枚举类型(enum)、函数类型(function);
引用类型:字符串(string)、数组(array)、结构体(structs)、映射(mapping)、不定长字节数组(bytes)
1、整型:
solitity中的整型与JavaScript不同,该类型支持有符号(int)或无符号(uint)两种类型,也支持从uint8到uint256,以及从int8到int256等多种类型。
2、地址类型(address)
以太坊中的地址的长度为20字节,一字节等于8位,一共160位,所以address其实亦可以用uint160来声明。
3、枚举类型(enum)
一个变量可能的取值都知道,就可以把它定义为枚举型,然后把变量的值一一列出来,令变量的值只限于列举出来的值的范围内。例如月份、星期几、天气等情况,枚举类型用enum关键字来定义。
例子:
enum weekday{sun,mon,tue,wed,the,fri,sat};
上面声明了一个枚举类型weekday(注意,这是一个类型,而不是一个变量,你可以用这个类型去声明变量),花括号中的sun mon等称为枚举元素,weekday的值只能是括号内的七个值。
在程序中可以用weekday.sun这种格式来引用枚举类型的值。
枚举元素的值在没有指定的情况下,第一个默认为0,往后的自增一,例如sun=0,mon=1,tue=2。有指定值的时候就用指定值,其后元素如果没有指定则自增一。
4、结构体(struct)
pragma solidity ^0.4.4;
contract Students {
struct Person {
uint age;
uint stuID;
string name;
}
}
上面定义的Students是一个结构体类型,不是变量。我们要声明一个结构体变量,要用下面的方法:
pragma solidity ^0.4.4;
contract Students {
struct Person {
uint age;
uint stuID;
string name;
}
// 初始化一个storage型的结构体变量_person
Person _person = Person(18,101,"liyuechun");
// 初始化一个memory类型的结构体变量person
function personInit() {
Person memory person = Person({age:18,stuID:101,name:"liyuechun"});
}
}
5、映射
字典/映射其实就是一个一对一键值存储关系。
语法:mapping(_KeyType => _ValueType)
举个例子:
1. 映射的数据结构
{age: 28, height: 178, name: liujing}
// 这就是一个映射,满足_KeyType => _ValueType之间的映射关系,age对应一个28的值,height对应178,name对应liujing。
2. 映射类型数据的声明
contract MappingExample {
mapping(address => uint) balances;
function update(address a,uint newBalance) public {
balances[a] = newBalance;
}
}
注意,mapping不是数据类型,mapping(address => uint)才是用来声明变量balances的数据类型。
6、数组
solidity中数组可以分为可变数组和不可变数组。
1)数组的创建
contract C {
uint [5] T = [1,2,3,4,5]; // 不可变数组,数组的长度为5,数组里面的存储的值的类型为uint类型
uint [] T = [1,2,3,4,5]; // 可变数组,因为总共只有5个数字,所以数组长度暂时为5
}
2)数组长度的更改:T.length
function setTLength(uint len) public {
T.length = len;
}
// 这种方法只可以用于可变数组,不可变数组的长度是不可以更改的
// 与JavaScript相比,这里没有length()方法,而是length属性
3)添加元素的方法:push()
function pushUintToT() public {
T.push(6);
}
// 同样的,该方法只用于可变数组,不可变数组不能使用该方法添加元素
4)创建memory数组
创建一个长度为length的memory类型的数组可以通过new关键字来创建。memory数组一旦创建,它不可通过length修改其长度。
contract C {
function f(uint len) {
uint[] memory a = new uint[](len);
a[6] = 8;
}
}
5)数组字面量 Array Literals / 内联数组 Inline Arrays
数组字面量,是指以表达式方式隐式声明一个数组,并作为一个数组变量使用的方式。下面是一个简单的例子:
contract C {
function f() {
// g([1,2,3]) 报错:传入的[1,2,3]是uint8的,按照声明时的要求必须是uint的,所以对第一个元素进行强制转换
g([uint(1), 2, 3]); // second step:调用g()函数
}
function g(uint[3] _data) { // first step:这里隐式声明了一个uint[3]类型的数组,memory的、定长的
// ...
}
}
通过数组字面量,创建的数组是memory的,同时还是定长的。
元素类型则是使用刚好能存储的元素的能用类型,比如代码里的[1, 2, 3],只需要uint8即可存储。由于g()方法的参数需要的是uint(默认的uint表示的其实是uint256),所以要使用uint(1)来进行类型转换。
还需注意的一点是,定长数组,不能与变长数组相互赋值,我们来看下面的代码:
contract C {
function f() {
// The next line creates a type error because uint[3] memory cannot be converted to uint[] memory.
uint[] x = [uint(1), 3, 4];
}
7、字符串、动态字节数组和固定字节数组及三者相互转换
1)字符串
string a = 'alkjljakf'
string 是一个动态尺寸的UTF-8编码字符串,它其实是一个特殊的可变字节数组;
Solidity中的字符串不像JavaScript中那样,没有length()方法,必须转换成字节数组才能使用length属性来获得长度;
2)固定大小字节数组(Fixed-size byte arrays)
contract C {
// 0x6c697975656368756e
byte public a = 0x6c; // 0110 1100 1个字节8位
bytes1 public b = 0x6c; // 0110 1100 1个字节8位
bytes2 public c = 0x6c69; // 0110 1100 0110 1001 2个字节16位
bytes3 public d = 0x6c6979; // 0110 1100 0110 1001 0111 1001 3个字节24位
// ...
bytes8 public f = 0x6c69797565636875; // 0110 1100 0110 1001 0111 1001 0111 0101 0110 0101 0110 0011 0110 1000 0111 0101
bytes9 public g = 0x6c697975656368756e; // // 0110 1100 0110 1001 0111 1001 0111 0101 0110 0101 0110 0011 0110 1000 0111 0101 0110 1110
}
固定大小字节数组可以通过 bytes1, bytes2, bytes3, …, bytes32来进行声明。PS:byte的别名就是 byte1。
length返回字节数组的元素个数
固定字节数组元素和长度均不能更改,普通定长数组长度不可改,但元素可以依靠索引来更改
3)动态大小字节数组(Dynamically-sized byte array)
string public name = "liyuechun";
bytes public g = 0x6c697975656368756e;
// 初始化一个两个字节空间的字节数组
bytes public name = new bytes(2);
bytes 动态字节数组,引用类型。
根据经验,在我们不确定字节数据大小的情况下,我们可以使用string或者bytes;
如果我们清楚的知道或者能够将字节书控制在bytes1 ~ bytes32,那么我们就使用bytes1 ~ bytes32,这样的话能够降低存储成本。
bytes类型可以使用push()方法,具有length属性
4)字符串、动态字节数组和固定字节数组及三者相互转换
string public name = "strange"
################################################
############# string转bytes ###############
################################################
function nameBytes() constant returns (bytes) {
return bytes(name); // 强制转换string为bytes
}
function nameLength() constant returns (uint) {
return bytes(name).length; //
}
function setNameFirstByteForL(bytes1 z) {
// 0x4c => "L"
bytes(name)[0] = z;
}
################################################
##### bytes1~bytes32固定字节数组之间相互转换 #####
################################################
bytes9 name9 = 0x6c697975656368756e;
bytes1(name9);
bytes2(name9);
bytes32(name9);
当bytes9转bytes1或者bytes2时,会进行低位截断,0x6c697975656368756e转换为bytes1,结果为0x6c,转换为bytes2时结果为0x6c69。
当bytes9转换为bytes32时会进行低位补齐,结果为0x6c697975656368756e0000000000000000000000000000000000000000000000。
################################################
##### 固定字节数组转bytes动态大小字节数组 ######
################################################
bytes9 name9 = 0x6c697975656368756e;
// 直接转换报错:固定大小字节数组和动态大小字节数组之间不能简单直接转换
bytes(name9);
// 固定大小字节数组转动态大小字节数组正确的姿势
bytes memory names = new bytes(name9.length);
for(uint i = 0; i < name9.length; i++) {
names[i] = name9[i];
}
################################################
####### 动态大小字节数组转string #######
################################################
bytes names = new bytes(2);
function C() {
names[0] = 0x6c;
names[1] = 0x69;
}
string(names)
################################################
##### 固定大小字节数组不能直接转换为string #####
################################################
因为string是特殊的动态字节数组,所以string只能和动态大小字节数组(Dynamically-sized byte array)之间进行转换;
固定大小字节数组要转换为String,必须先转换成动态大小字节数组,再转换为string。
有时候会因为字节问题,转换成字符串后会有很多多余的字符u0000,所以:
// 完整的固定大小字节数组转string的代码
contract C {
function bytes32ToString(bytes32 x) constant returns (string) {
bytes memory bytesString = new bytes(32);
uint charCount = 0;
for (uint j = 0; j < 32; j++) {
byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
if (char != 0) {
bytesString[charCount] = char;
charCount++;
}
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (j = 0; j < charCount; j++) {
bytesStringTrimmed[j] = bytesString[j];
}
return string(bytesStringTrimmed);
}
function bytes32ArrayToString(bytes32[] data) constant returns (string) {
bytes memory bytesString = new bytes(data.length * 32);
uint urlLength;
for (uint i = 0; i< data.length; i++) {
for (uint j = 0; j < 32; j++) {
byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
if (char != 0) {
bytesString[urlLength] = char;
urlLength += 1;
}
}
}
bytes memory bytesStringTrimmed = new bytes(urlLength);
for (i = 0; i < urlLength; i++) {
bytesStringTrimmed[i] = bytesString[i];
}
return string(bytesStringTrimmed);
}
}