基本类型之间的转换¶
隐式转换¶
如果一个运算符用在两个不同类型的变量之间,那么编译器将隐式地将其中一个类型转换为另一个类型(不同类型之间的赋值也是一样)。
一般来说,只要值类型之间的转换在语义上行得通,而且转换的过程中没有信息丢失,那么隐式转换基本都是可以实现的:
uint8
可以转换成 uint16
,int128
转换成 int256
,但 int8
不能转换成 uint256
(因为 uint256
不能涵盖某些值,例如,-1
)。
更进一步来说,无符号整型可以转换成跟它大小相等或更大的字节类型,但反之不能。
显式转换¶
如果某些情况下编译器不支持隐式转换,但是你很清楚你要做什么,这种情况可以考虑显式转换。
注意这可能会发生一些无法预料的后果,因此一定要进行测试,确保结果是你想要的!
下面的示例是将一个 int8
类型的负数转换成 uint
:
int8 y = -3;
uint x = uint(y);
这段代码的最后,x
的值将是 0xfffff..fd
(64 个 16 进制字符),因为这是 -3 的 256 位补码形式。
如果一个类型显式转换成更小的类型,相应的高位将被舍弃
uint32 a = 0x12345678;
uint16 b = uint16(a); // 此时 b 的值是 0x5678
如果将整数显式转换为更大的类型,则将填充左侧(即在更高阶的位置)。 转换结果依旧等于原来整数
uint16 a = 0x1234;
uint32 b = uint32(a); // b 为 0x00001234 now
assert(a == b);
定长字节数组转换则有所不同, 他们可以被认为是单个字节的序列和转换为较小的类型将切断序列
bytes2 a = 0x1234;
bytes1 b = bytes1(a); // b 为 0x12
如果将定长字节数组显式转换为更大的类型,将按正确的方式填充。 以固定索引访问转换后的字节将在和之前的值相等 (如果索引仍然在范围内):
bytes2 a = 0x1234;
bytes4 b = bytes4(a); // b 为 0x12340000
assert(a[0] == b[0]);
assert(a[1] == b[1]);
因为整数和定长字节数组在截断(或填充)时行为是不同的, 如果整数和定长字节数组有相同的大小,则允许他们之间进行显式转换, 如果要在不同的大小的整数和定长字节数组之间进行转换 ,必须使用一个中间类型来明确进行所需截断和填充的规则:
bytes2 a = 0x1234;
uint32 b = uint16(a); // b 为 0x00001234
uint32 c = uint32(bytes4(a)); // c 为 0x12340000
uint8 d = uint8(uint16(a)); // d 为 0x34
uint8 e = uint8(bytes1(a)); // e 为 0x12
字面常量与基本类型的转换¶
整型与字面常量转换¶
十进制和十六进制字面常量可以隐式转换为任何足以表示它而不会截断的整数类型
uint8 a = 12; // 可行
uint32 b = 1234; // 可行
uint16 c = 0x123456; // 失败, 会截断为 0x3456
定长字节数组与字面常量转换¶
十进制字面常量不能隐式转换为定长字节数组。十六进制字面常量可以是,但仅当十六进制数字大小完全符合定长字节数组长度。 不过零值例外,零的十进制和十六进制字面常量都可以转换为任何定长字节数组类型:
bytes2 a = 54321; // 不可行
bytes2 b = 0x12; // 不可行
bytes2 c = 0x123; // 不可行
bytes2 d = 0x1234; // 可行
bytes2 e = 0x0012; // 可行
bytes4 f = 0; // 可行
bytes4 g = 0x0; // 可行
字符串字面常量和十六进制字符串字面常量可以隐式转换为定长字节数组,如果它们的字符数与字节类型的大小相匹配:
bytes2 a = hex"1234"; // 可行
bytes2 b = "xy"; // 可行
bytes2 c = hex"12"; // 不可行
bytes2 d = hex"123"; // n不可行
bytes2 e = "x"; // 不可行
bytes2 f = "xyz"; // 不可行
类型推断(已弃用)¶
为了方便起见,没有必要每次都精确指定一个变量的类型,编译器会根据分配该变量的第一个表达式的类型自动推断该变量的类型
uint24 x = 0x123;
var y = x;
这里 y
的类型将是 uint24
。不能对函数参数或者返回参数使用 var
。
警告
类型只能从第一次赋值中推断出来,因此以下代码中的循环是无限的,
原因是``i`` 的类型是 uint8
,而这个类型变量的最大值比 2000
小。
for (var i = 0; i < 2000; i++) { ... }