类型
状态类型:Solidity 提供了几种基本类型,并且基本类型可以用来组合出复杂类型。
注意:“undefined”或“null”值的概念在Solidity中不存在。
值类型:
-
布尔类型
bool:
true
和false
-
整型
int:有符号的不同位数的整形变量 (int8,int256) 一般int认为是256位
uint:无符号的不同位数的整型变量 ( uint8,uint256)一般uint认为是256位
Solidity中的整数是有取值范围的。 例如 uint32
类型的取值范围是 0
~ 2^32-1;如果数值为2^32,会落到取值范围以外,进行溢出,故而通过失败异常进行调用回退。
-
定长浮点型
fixed:有符号的定长浮点型,一般fixed默认为fixed128x18r
ufixed:无符号的定长浮点型,一般ufixed默认为ufixed128x18
在关键字ufixedMxN和fixedMxN中,M表示该类型占用的位数,N表示可用的小数位数
M必须能够整除8,并且从8到256位
N必须介于0-80之间,包括0和80
-
地址类型Address
两种类型:
address:保存一个20字节的值(以太坊地址的大小)160位
address payable:可支付地址,与
address
相同,不过有成员函数transfer
和send
。其实address payable可以接受以太币的地址,而一个普通的
address
则不能。类型转化:
从
address payable
到address
的转换 ,使用 payable(<address>)
address
允许和uint160
、 整型字面常量、bytes20
及合约类型相互转换。//只能通过
payable(...)
表达式把address
类型和合约类型转换为address payable
。 只有能接收以太币的合约类型,才能够进行此转换。例如合约要么有 receive 或可支付的回退函数。
1.<address>.balance (uint256)
//以 Wei 为单位的 查询地址类型 Address 的余额。
2.<address payable>.transfer(uint256 amount)
//向 地址类型payable Address 发送数量为 amount 的 Wei。失败时抛出异常,使用固定(不可调节)的 2300 gas 的矿工费。
/*如果 x 是一个合约地址,它的代码(更具体来说是, 如果有receive函数, 执行 receive 接收以太函数, 或者存在fallback函数,执行 Fallback 回退函数 函数)会跟 transfer 函数调用一起执行(这是 EVM 的一个特性,无法阻止)。 如果在执行过程中用光了 gas 或者因为任何原因执行失败,以太币Ether 交易会被打回,当前的合约也会在终止的同时抛出异常。*/
address x = 0x123;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
3.<address payable>.send(uint256 amount) returns (bool)
//向 地址类型 Address 发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。当前的合约不会因为异常而终止
4.<address>.code (bytes memory)
//在 地址类型 Address 上的代码(可以为空)
5.<address>.codehash (bytes32)
//`address`的codehash
//以下三类是为了与不符合应用二进制接口的合约交互
6.<address>.call(bytes memory) returns (bool, bytes memory)
//用给定的有效载荷(payload)发出低级 CALL 调用,返回成功状态及返回数据,发送所有可用 gas,也可以调节 gas。
bytes memory payload = abi.encodeWithSignature("register(string)", "MyName");
(bool success, bytes memory returnData) = address(nameReg).call(payload);
require(success);
7.<address>.delegatecall(bytes memory) returns (bool, bytes memory)
//用给定的有效载荷 发出低级 DELEGATECALL 调用 ,返回成功状态并返回数据,发送所有可用 gas,也可以调节 gas。 发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas,可调节。
8.<address>.staticcall(bytes memory) returns (bool, bytes memory)
//用给定的有效载荷 发出低级 STATICCALL 调用 ,返回成功状态并返回数据,发送所有可用 gas,也可以调节 gas。
-
合约类型
每一个合约定义都有他自己的类型。
合约和
address
的数据表示是相同的合约不支持任何运算符。
合约类型的成员是合约的外部函数及 public 的 状态变量。
-
定长字节数组
关键字有:
bytes1
,bytes2
,bytes3
, …,bytes32
。其实字节的意思可以将
byte[]
当作字节数组使用,但这种方式非常浪费存储空间,准确来说,是在传入调用时,每个元素会浪费 31 字节。 更好地做法是使用bytes
。成员变量:.length 表示这个字节数组的长度(只读).
-
变长字节数组
bytes
:变长字节数组,它并不是值类型。
string
:变长 UTF-8 编码字符串类型。并不是值类型。
-
地址字面常量
比如像
0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF
这样的通过了地址校验和测试的十六进制字面常量会作为address
类型。 而没有通过校验测试, 长度在 39 到 41 个数字之间的十六进制字面常量,会产生一个错误,您可以在零前面添加(对于整数类型)或在零后面添加(对于bytesNN类型)以消除错误。
-
有理数和整数字面常量
整数字面常量由范围在 0-9 的一串数字组成,表现成十进制。 例如,69 表示数字 69。 Solidity 中是没有八进制的,因此前置 0 是无效的。
-
字符串字面常量及其类型
字符串字面常量是指由双引号或单引号引起来的字符串
和整数字面常量一样,字符串字面常量的类型也可以发生改变,但它们可以隐式地转换成
bytes1
,……,bytes32
,如果合适的话,还可以转换成bytes
以及string
。
bytes32 samevar = "stringliteral"
//字符串字面常量在赋值给 bytes32 时被解释为原始的字节形式。
//此外,字符串字面常量支持下面的转义字符:
\<newline> (转义实际换行)
\\ (反斜杠)
\' (单引号)
\" (双引号)
\b (退格)
\f (换页)
\n (换行符)
\r (回车)
\t (标签 tab)
\v (垂直标签)
\xNN (十六进制转义,见下文) // \xNN 表示一个 16 进制值,最终转换成合适的字节,而 \uNNNN 表示 Unicode 编码值,最终会转换为 UTF-8 的序列。
\uNNNN (unicode 转义,见下文)
-
Unicode字面常量
常规字符串文字只能包含ASCII,而Unicode文字(以关键字unicode为前缀)可以包含任何有效的UTF-8序列。 它们还支持与转义序列完全相同的字符作为常规字符串文字。
string memory a = unicode"Hello 😃";
-
十六进制字面常量
十六进制字面常量以关键字
hex
打头,后面紧跟着用单引号或双引号引起来的字符串(例如,hex"001122FF"
)。 字符串的内容必须是一个十六进制的字符串,它们的值将使用二进制表示。用空格分隔的多个十六进制字面常量被合并为一个字面常量:
hex"00112233" hex"44556677"
等同于hex"0011223344556677"
-
枚举类型
枚举是在Solidity中创建用户定义类型的一种方法。 它们是显示所有整型相互转换,但不允许隐式转换。 从整型显式转换枚举,会在运行时检查整数时候在枚举范围内,否则会导致异常。 枚举需要至少一个成员,默认值是第一个成员,枚举不能多于 256 个成员。
-
函数类型
1.两类
- 内部(internal) 函数类型。 只能在当前合约内被调用,因为它们不能在当前合约上下文的外部被执行。 调用一个内部函数是通过跳转到它的入口标签来实现的。一般函数默认的就是内部函数类型。
- 外部(external) 函数类型。外部函数由一个地址和一个函数签名组成,可以通过外部函数调用传递或者返回。
2.类型转化
pure
函数可以转换为view
和non-payable
函数view
函数可以转换为non-payable
函数payable
函数可以转换为non-payable
函数关于
payable
和non-payable
的规则可能有点令人困惑,但实质上,如果一个函数是payable
,这意味着它 也接受零以太的支付,因此它也是non-payable
。 另一方面,non-payable
函数将拒绝发送给它的 以太币Ether , 所以non-payable
函数不能转换为payable
函数。(单向转化)注意,当前合约的 public 函数既可以被当作内部函数也可以被当作外部函数使用。 如果想将一个函数当作内部函数使用,就用
f
调用,如果想将其当作外部函数,使用this.f
。3.成员方法
public(或 external)函数都有下面的成员:
.address
返回函数的合约地址。.selector
返回 ABI 函数选择器
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.4 <0.9.0;
contract Example {
function f() public payable returns (bytes4) {
assert(this.f.address == address(this));
return this.f.selector;
}
function g() public {
this.f{gas: 10, value: 800}();
}
}
运算:
!
(逻辑非)&&
(逻辑与, “and” )||
(逻辑或, “or” )==
(等于)!=
(不等于)- 比较运算符:
<=
,<
,==
,!=
,>=
,>
(返回布尔值) - 位运算符:
&
,|
,^
(异或),~
(位取反) - 移位运算符:
<<
(左移位) ,>>
(右移位) - 算数运算符:
+
,-
, 一元运算负-
(仅针对有符号整型),*
,/
,%
(取余或叫模运算) ,**
(幂)- 加减乘和正常语法一样,不过会有溢出异常。整数除法总是产生整数。 在Solidity中,分数会取零。
- 模运算中,
a%n
是在操作数a
的除以n
之后产生余数r
。
- 对于负数的除法,结果的正负号取决于被除数是否为正负号
int256(5) % int256(2) == int256(1)
int256(5) % int256(-2) == int256(1)
int256(-5) % int256(2) == int256(-1)
int256(-5) % int256(-2) == int256(-1)
对于整形 X
,可以使用 type(X).min
和 type(X).max
去获取这个类型的最小值与最大值。
位运算:位运算在数字的二进制补码表示上执行。 这意味着: ~int256(0)== int256(-1)
。
移位:
- 不管
x
正还是负,x << y
相当于x * 2 ** y
。- 如果
x
为正值,x >> y
相当于x / 2 ** y
。- 如果
x
为负值,x >> y
相当于(x + 1) / 2**y - 1
(与将x
除以2**y
同时向负无穷大四舍五入)。