
基础类型之间的转换
隐式转换
隐式类型转换是在某些场景下由编译器自动执行的操作,例如赋值、函数参数传递或应用运算符时。通常,只有在值类型之间转换不会导致语义歧义或信息丢失的情况下,才会发生隐式转换。
例如,uint8 可以转换为 uint16,int128 可以转换为 int256,但 int8 不能转换为 uint256,因为 uint256 无法表示负数(如 -1)。
当对不同类型的操作数应用运算符时,编译器会尝试将其中一个操作数隐式转换为另一个操作数的类型(赋值操作时也是如此)。这意味着运算将始终在某一方的类型下执行。
关于哪些隐式转换是允许的,请参阅相关类型的具体章节。
例如,y 和 z 是两个加法操作数,它们的类型不同,但由于 uint8 可以隐式转换为 uint16,而 uint16 不能隐式转换为 uint8,所以在运算执行前,y 会被转换为 z 的类型,即 uint16。表达式 y + z 的结果类型为 uint16,然后由于赋值给 uint32 类型的变量,因此结果又会被隐式转换为 uint32。
uint8 y;
uint16 z;
uint32 x = y + z;
显式转换
当编译器不允许隐式转换时,若你确信转换是安全的,可以使用显式类型转换。然而,这种操作可能会引发非预期行为,并绕过编译器的一些类型安全检查,因此务必确保转换结果符合预期,并进行充分测试。
以下是一个将负数 int 转换为 uint 的示例:
int y = -3;
uint x = uint(y);
在上述代码中,x 的值将为 0xffff…fd(共 64 个十六进制字符),这是 -3 在 256 位二进制补码表示中的形式。
若将整数显式转换为更小的类型,高位将会被截断:
uint32 a = 0x12345678;
uint16 b = uint16(a); // b 现在将是 0x5678
若将整数显式转换为更大的类型,转换结果将在高位进行零填充,即保留原始整数的数值:
uint16 a = 0x1234;
uint32 b = uint32(a); // b 现在将是 0x00001234
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
动态字节数组(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); // 如果 m 的长度大于 16,将发生截断
b = bytes16(s); // 右侧填充零,结果为 "abcdefgh\0\0\0\0\0\0\0\0"
bytes3 b1 = bytes3(s); // 截断,b1 等于 "abc"
b = bytes16(c[:8]); // 也用零填充
return (b, b1);
}
}
关键点:
1.显式转换可以绕过编译器的类型检查,需谨慎使用。
2.转换为更小类型时将截断高位;转换为更大类型时将高位填充零。
3.固定大小字节数组在转换过程中会根据目标类型大小截断或填充。
2398

被折叠的 条评论
为什么被折叠?



