Solidity 数据类型可以大致分为以下两种类型:
这两种类型在变量赋值和存储在 EVM
中的方式方面有所不同。值类型维护变量的独立副本,并且在一个变量中更改值不会影响另一个变量中的值。但是,更改引用类型变量中的值可确保任何引用该变量的地方都会获取更新值。
如果一个类型将数据(值)直接保存在内存中,则称该类型为值类型。
值类型是大小不超过32字节内存的类型。Solidity 提供以下值类型:
bool
:可以保存 true 或 false 作为其值的布尔值uint
:这是无符号整数,只能保存0和正值int
:这是可以保存负值和正值的有符号整数address
:这表示以太坊环境中的账户地址byte
:这表示固定大小的字节数组(byte1
到 bytes32
)整数有助于将数字存储在合约中。Solidity
提供以下两种类型的整数:
对于每种类型,Solidity
都有多种类型的整数。Solidity
提供了 uint8
类型来表示8位无符号整数,并且以8的倍数表示,直到达到256。总之,可以声明32个不同的具有8的倍数的无符号整数,例如 uint8
、uint16
、unit24
、uint256
位。同样,有符号整数的数据类型也是相同的,如 int8
、int16
,直到 int256
。
根据要求,应选择适当大小的整数。例如,当存储0〜255之间的值时,uint8
是合适的,而存储介于-128〜127 之间则 int8
更合适。对于更高的值,可以使用更大的整数。
有符号和无符号整数的缺省值为零,在声明时它们会自动初始化。
可以对整数执行数学运算,例如加法、减法、乘法、除法、指数、否定、后增量和预增量
像任何编程语言一样,Solidity
提供了一种布尔数据类型。bool
数据类型可用于表示具有二进制结果的场景,例如 true
或 false
、1或0等。此数据类型的有效值为 true
和 false
。值得注意的是,Solidity 中的布尔不能转换为整数,就像它们在其他编程语言中一样。它是一个值类型,任何赋值给其他的布尔变量都会创建一个新副本。Solidity
中 bool
的默认值为 false
。
声明和赋值 bool
数据类型的代码如下:
bool isPaid = true;
字节是指8位有符号整数。内存中的所有内容都存储在由二进制值0和1组成的位中。Solidity
还提供字节数据类型以存储二进制格式信息。通常,编程语言只有一种数据类型来表示字节。但是,Solidity
具有多种字节类型。它提供的数据类型范围为 bytes1
〜bytes32
(含),以根据需要表示不同的字节长度。这些被称为固定大小的字节数组,并被实现为值类型。bytes1
数据类型代表1个字节,bytes2
代表2个字节。字节的默认值是 0x00
,并用此值初始化。Solidity
也有一个 byte
类型,它是 bytes1
的别名。
一个字节可以以十六进制格式赋值,如下所示:
bytes1 aa = 0x65;
一个字节可以被赋值为十进制格式的整数值,如下所示:
bytes1 bb = 10;
一个字节可以被赋值为十进制格式的负整数值,如下所示:
bytes1 ee = -100;
一个字节可以赋值为字符值,如下所示:
bytes1 dd = 'a';
在下面的代码片段中,256不适合放入单个字节,需要更大的字节数组:
bytes2 cc = 256;
枚举是包含一个预定义的常量值列表的值类型。它们通过值传递,每个副本都维护自己的值。不能在函数内声明枚举,并在合约的全局域命名空间内声明。预定义的常量是连续赋值的,从零开始增加整数值。如:
enum status {created, approved, provisioned, rejected, deleted}
地址是20字节的数据类型。它是为了存储以太坊中的账户地址而特别设计的,其大小为160位或20字节。它可以保存合约账户地址以及外部拥有的账户地址。地址是一种值类型,它被赋值给另一个变量时会创建一个新副本。
地址具有 balance 属性,该属性返回账户可用的以太币数量,并具有一些用于账户间交易以太币和调用合约函数的功能。
它提供以下两个函数来交易以太币:
当向一个账户发送以太币时,更应该选择 transfer 函数而不是send函数。send 函数返回一个布尔值,具体取决于以太币发送是否成功执行,而 transfer 函数引发异常并将以太币返还给调用者。
它还提供了以下三个用于调用合约函数的函数:
引用类型不直接将其值存储在变量本身中。它们存储的不是值,而是值存储位置的地址。该变量保存了指向另一个实际存储数据的内存位置的指针。
Solidity 提供以下引用类型:
数组是数据类型,但更具体地说,它们是依赖于其他数据类型的数据结构。数组是指相同类型的数值组。数组有助于将这些值存储在一起,并简化迭代、排序和搜索该组中元素或子元素的过程。Solidity 提供了丰富的数组结构,可以满足不同的需求。
Solidity 中的数组示例如下:
uint[5] intArray
Solidity 中的数组可以是固定的或动态的。
固定数组
固定数组是指声明了预定大小的数组。固定数组的例子如下:
int[5] age;
byte[4] flags;
固定数组无法使用new
关键字进行初始化。它们只能以内联方式初始化,如下面的代码所示:
int[5] age = [1,2,3,4,5];
它们也可以稍后在函数中内联初始化,如下所示:
int[5] age;
age = [1,2,3,4,5];
动态数组
动态数组是指在声明时没有预定大小的数组,但是,它们的大小是在运行时确定的。看看下面的代码:
int[] age;
byte[] flags;
动态数组可以内联初始化,可以在声明时初始化,如下所示:
int[] age = [1,2,3,4,5];
特殊数组
Solidity 提供了以下两个特殊数组:
a.字节数组:
字节数组是一个动态数组,可以容纳任意数量的字节。它与byte[]
不同。byte[]
数组每个元素占用32个字节,而字节数组紧紧地将所有字节保存在一起。
字节可以声明为具有初始长度大小的状态变量,如以下代码所示:
bytes localBytes = new bytes(0);
这也可以分成与以前讨论的数组类似的以下两条代码行:
bytes localBytes;
localBytes = new bytes(10);
字节数组可以直接赋值,如下所示:
localBytes = "solidity is good";
此外,如果数据位于存储位置,则可以将值压栈其中,如下面的代码所示:
localBytes.push(byte(10));
字节数组还提供读/写长度属性,如下所示:
return localBytes.length;
localBytes.length = 4;
b.字符串数组
字符串是基于上一节讨论的字节数组的动态数据类型。它们与附加约束的字节数组非常相似。字符串不能被索引或压栈,也不具有 length 属性。要对字符串变量执行任何这些操作,应首先将其转换为字节,然后在操作后将其转换回字符串。
字符串可以由单引号或双引号内的字符组成。字符串可以直接声明并赋值,如下所示:
String name = "mike";
它们也可以转换为字节,如下所示:
Bytes byteName = bytes(name);
数组属性
数组支持一些基本的属性。在 Solidity 中,由于有多种类型的数组,并非每种类型都支持所有这些属性。
这些属性如下所示:
结构或结构体有助于实现自定义的用户数据类型。结构是一种复合数据类型,由多个不同数据类型的变量组成。它们与合约非常相似,但是,它们不包含任何代码。它们只包含变量。
Solidity 的结构中的 struct 关键字进行声明。结构中的变量在花括号{}内定义,如图所示:
struct user {
string name;
uint age;
int id;
address addr;
}
使用下面的语法来创建一个结构的实例。不需要显式调用关键字 new。关键字new只用于创建合约或者数组的实例,如图所示:
student = user("LiMing", 23, 1, 0xc6a115f2abc09746963d6a6800bd82157d27d8e7);
映射是 Solidity
中最常用的复杂数据类型之一。映射类似于其他语言中的散列表或字典。它们存储键值对,并允许根据提供的键来检索值。
使用 mapping
关键字声明映射,后跟由=>表示法分隔的键和值的数据类型。映射具有与任何其他数据类型一样的标识符,并且它们可用于访问映射。
一个声明映射的例子如下:
mapping(uint => address) Names;
在前面的代码中,uint
数据类型用于存储键而 address
数据类型用于存储值。Names
用作映射的标识符。
虽然它类似于散列表和字典,但 Solidity
不允许迭代映射。如果键已知,则可以检索映射中的值。下一个示例说明如何使用映射。合约中维护有一个 uint
类型的计数器作为映射的键,并且在函数的帮助下存储和检索地址详细信息。
要访问映射中的任何特定值,相关键应与映射名一起使用,如下所示:
Names[uint(3)]
要在映射中存储值,请使用以下语法:
Names[uint(4)] = 0xc6a115f2abc09746963d6a6800bd82157d27d8e7