Solidity 数据类型
睡不醒的鲤鱼 2022-12-28 Web3 Solidity
# 一、一些 Tips
# 1.1 区分大小写
Solidity 语言是大小写敏感的,下面是两个不同合约的定义。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Test {
}
contract TEST {
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 1.2 注释
Solidity 有两种类型的注释:
- 单行注释以
//
开头。 - 多行注释以
/*
开头,以*/
结束。
# 1.3 注释注解
@dev
:声明合约或函数。@param
:声明函数入参。@return
:声明函数返回类型。
# 1.4 代码块
代码块表示一系列应该按顺序执行的语句,这些语句被封装在 {
和 }
之间。
# 1.5 声明变量
Solidity 一行只能声明一个变量,不支持声明多个变量。
# 1.6 命名变量
- 必须以字母、
_
或$
开头; - 除第一个字符,其他字符可以是字母、
_
、$
或数字。
# 1.7 声明变量是必须的
Solidity 要求必须为每个变量声明类型(包括 var 类型),否则会报错。
# 二、简单类型
# 2.1 字符串类型
String
- 字符串字面量是指由
'
或"
包围起来的字符串。字符串不同于 C 语言,是不包含结束符的。 - 字符串类型在 Solidity 语法中支持 bytes、bytesN、string 三种类型。
- String 是一个动态的 UTF-8 编码字符串,属于引用类型。
- String 字符串没有提供获取字符串长度、索引取值、push 追加字节的方法。这里有一个解决方案是将 string 转换为 bytes 来进行相关操作。
Bytes
bytes(name)
可以将字符串name
转换为 bytes 类型。- bytes 类型可以直接使用获取长度、索引取值赋值、push 追加等操作,如
bytes(name).length
。 - string 和 bytes 类型之间可以直接进行类型转换。
- 对于变长类型的字符串,不支持一般的比较运算符。如需比较,需要遍历单个 bytes 进行比较。
# 2.2 整数类型
整数类型分为有符号或无符号整型。变量支持的步长以 8 递增,支持从 uint8 到 uint256,以及 int8 到 int256,uint 和 int 默认的是 uint256 和 int256。
- uint8 的存储范围为
- int8 的存储范围为
Solidity 支持以下运算符:
- 比较:
<=
,<
,==
,!=
,>=
,>
,返回值为 bool 类型。 - 位运算符:
&
与,|
或,^
异或,~
非。 - 数学运算:
+
,-
,*
,/
,%
取余,**
乘方,<<
左移(乘 ),>>
右移(除以 )。
Solidity 目前没有支持 double 或 float,如果 7 / 2
会得到 3,即无条件舍去。除以 0 会抛出异常。
# 2.3 布尔类型
- 布尔类型的取值为常量值 true 和 false。
- 支持的运算符包括:
!
,&&
,||
,==
,!=
。
# 2.4 地址类型
- 以太坊中的地址长度为 20 字节,一共 160 位,因此 address 类型也可以用 uint160 来声明。
- address 类型支持比较运算符:
<=
,<
,==
,!=
,>=
,>
。 - address 包含成员变量
balance
以及成员方法send()
。
# 2.5 枚举类型
枚举类型是在 Solidity 中的一种用户自定义类型,其中至少要有一个元素,如下所示。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Enum {
// 声明枚举类型
enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
FreshJuiceSize choice;
FreshJuiceSize constant defaultChoice = FreshJuiceSize.MEDIUM;
// 通过 . 来访问
function setLarge() public {
choice = FreshJuiceSize.LARGE;
}
function getChoice() public view returns (FreshJuiceSize) {
return choice;
}
// 可以显示的与整数进行转换,但不能隐式转换
function getDefaultChoice() public pure returns (uint) {
return uint(defaultChoice);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 三、复杂类型
# 3.1 结构体类型
- struct 就是一个实体,包含了特定实体的属性。
- struct 可以作为映射和数组中的元素,本身也可以包含映射和数组等类型。
- 不能在声明一个 struct 的同时将这个 struct 作为自身的一个成员,因为数据结构的大小必须有限。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Struct {
// 结构体定义
struct Book {
string title;
string author;
uint bookId;
// 编译错误,不允许递归定义
// Book book;
}
Book book1;
Book book2;
// 两种结构体初始化方法
function setBook() public {
// 默认初始化 Storage 中的状态变量
book1 = Book("Learn Solidity", "xyz", 1);
book2 = Book({title:"Learn Solidity", author:"xyz", bookId:1});
// 指定初始化 memory 中的状态变量
Book memory book3 = Book("Learn Solidity", "xyz", 1);
Book memory book4 = Book({title:"Learn Solidity", author:"xyz", bookId:1});
}
// 通过 . 来访问或修改结构体中的属性
function getBookId() public view returns (uint) {
return book1.bookId;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 3.3 数组类型
- 数组可以在声明时指定长度,或者是变长的。
- 定长数组不能与变长数组相互赋值。
- 对于 Storage 的数组来说,元素类型可以是任意的;但对于 Memory 的数组来说,元素类型不能是映射类型的。
- 一个类型为 T,长度为 k 的数组,声明方式为
T[k]
,而一个变长的数组的声明方式为T[]
。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Array {
// 数组初始化,两种方式初始化的数组相同
uint[3] a = [1, 2, 3];
// 可以省略数组长度
uint[] b = [1, 2, 3];
// 访问数组元素
uint c = b[2];
function test() public {
// 变长数组通过 push 添加元素
b.push(4);
// 初始化 memory 数组
// 数组的基本类型是列表上的第一个表达式的类型
uint[3] memory d = [uint(1), 2, 3];
uint[] memory e = new uint[](7);
// 编译错误,memory 数组元素不能是映射类型
// mapping(uint => string)[] memory f;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 3.4 映射类型
映射类型,是一种键值对的映射关系存储结构。定义方式为 mapping(KeyType => ValueType)
,其中:
KeyType
可以是任何基本类型,即不包括映射、结构体以及数组(bytes 和 string 除外);ValueType
可以是包括映射类型在内的任何类型。
映射是没有长度的,也没有 key 的集合或 value 的集合的概念。映射也没有排序的概念。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Mapping {
mapping(address => uint) public balances;
uint balance;
function update(uint amount) public returns (uint) {
// 设置 mapping 中的值
balances[msg.sender] = amount;
// 取出 mapping 中的值
balance = balances[msg.sender];
return balance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 四、特殊变量
# 4.1 以太币单位
- 数字后面可以加后缀,表示以太币单位,包括
wei
,gwei
,ether
。 - 如果以太币数量后面没有单位,默认为
wei
。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Eth {
function test() public {
assert(1 wei == 1);
assert(1 gwei == 1e9);
assert(1 ether == 1e18);
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 4.2 时间单位
- 数字后面可以加后缀,表示时间单位,包括
seconds
,minutes
,hours
,days
和weeks
。 - 如果时间数字后没有单位,默认为
seconds
。 now
是当前时间戳。
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Time {
function test() public {
assert(1 == 1 seconds);
assert(1 minutes == 60 seconds);
assert(1 hours == 60 minutes);
assert(1 days == 24 hours);
assert(1 weeks == 7 days);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
这些后缀不能直接用在变量后边。如果想用时间单位(例如 days
)来将输入变量换算为时间,可以用如下方式来完成:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Time {
function f(uint start, uint daysAfter) public {
if (block.timestamp >= start + daysAfter * 1 days) {
// ...
}
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10