基本类型之间的转换
隐式转换
在某些情况下,编译器会在赋值期间、将参数传递给函数以及应用运算符时自动应用隐式类型转换。一般来说,如果在语义上有意义并且没有信息丢失,则值类型之间的隐式转换是可能的。
例如,uint8
可转换为 uint16
和int128
,int256
但int8
不可转换为uint256
,因为uint256
不能保存诸如 之类的值-1
。
如果将运算符应用于不同的类型,编译器会尝试将其中一个操作数隐式转换为另一个操作数的类型(赋值也是如此)。这意味着操作总是以操作数之一的类型执行。
有关可以进行哪些隐式转换的更多详细信息,请参阅有关类型本身的部分。
在下面的示例中,加法的操作数y
和z
不具有相同的类型,但uint8
可以隐式转换为uint16
,反之亦然。因此, 在类型中执行加法之前y
转换为类型。表达式的结果类型是。因为它被分配给类型的变量,所以在添加之后执行另一个隐式转换。z
uint16
y + z
uint16
uint32
uint8 y; uint16 z; uint32 x = y + z;
显式转换
如果编译器不允许隐式转换,但您确信转换会起作用,则有时可以进行显式类型转换。这可能会导致意外行为并允许您绕过编译器的某些安全功能,因此请务必测试结果是否符合您的要求!
举一个将负数转换为 a 的int
示例uint
:
int y = -3; uint x = uint(y);
在此代码片段的末尾,x
将具有值0xfffff..fd
(64 个十六进制字符),在 256 位的二进制补码表示中为 -3。
如果将整数显式转换为更小的类型,则高阶位被截断:
uint32 a = 0x12345678; uint16 b = uint16(a); // b will be 0x5678 now
如果一个整数被显式转换为一个更大的类型,它会被填充到左边(即在高阶端)。转换的结果将等于原始整数:
uint16 a = 0x1234; uint32 b = uint32(a); // b will be 0x00001234 now assert(a == b);
固定大小的字节类型在转换过程中表现不同。它们可以被认为是单个字节的序列,转换为更小的类型将切断序列:
bytes2 a = 0x1234; bytes1 b = bytes1(a); // b will be 0x12
如果将固定大小的字节类型显式转换为更大的类型,则会在右侧填充。访问固定索引处的字节将导致转换前后的值相同(如果索引仍在范围内):
bytes2 a = 0x1234; bytes4 b = bytes4(a); // b will be 0x12340000 assert(a[0] == b[0]); assert(a[1] == b[1]);
由于整数和固定大小的字节数组在截断或填充时表现不同,因此仅允许整数和固定大小的字节数组之间的显式转换,前提是两者具有相同的大小。如果要在整数和不同大小的固定大小字节数组之间进行转换,则必须使用中间转换来明确所需的截断和填充规则:
bytes2 a = 0x1234; uint32 b = uint16(a); // b will be 0x00001234 uint32 c = uint32(bytes4(a)); // c will be 0x12340000 uint8 d = uint8(uint16(a)); // d will be 0x34 uint8 e = uint8(bytes1(a)); // e will be 0x12
bytes
数组和bytes
calldata 切片可以显式转换为固定字节类型(bytes1
/…/ bytes32
)。如果数组比目标固定字节类型长,最后会发生截断。如果数组比目标类型短,则将在末尾用零填充。
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.5; contract C { bytes s = "abcdefgh"; function f(bytes calldata c, bytes memory m) public view returns (bytes16, bytes3) { require(c.length == 16, ""); bytes16 b = bytes16(m); // if length of m is greater than 16, truncation will happen b = bytes16(s); // padded on the right, so result is "abcdefgh\0\0\0\0\0\0\0\0" bytes3 b1 = bytes3(s); // truncated, b1 equals to "abc" b = bytes16(c[:8]); // also padded with zeros return (b, b1); } }