阅读(2623) (11)

基本类型之间的转换

2022-05-12 10:23:02 更新

隐式转换

在某些情况下,编译器会在赋值期间、将参数传递给函数以及应用运算符时自动应用隐式类型转换。一般来说,如果在语义上有意义并且没有信息丢失,则值类型之间的隐式转换是可能的。

例如,uint8可转换为 uint16int128int256int8不可转换为uint256,因为uint256不能保存诸如 之类的值-1

如果将运算符应用于不同的类型,编译器会尝试将其中一个操作数隐式转换为另一个操作数的类型(赋值也是如此)。这意味着操作总是以操作数之一的类型执行。

有关可以进行哪些隐式转换的更多详细信息,请参阅有关类型本身的部分。

在下面的示例中,加法的操作数yz不具有相同的类型,但uint8可以隐式转换为uint16,反之亦然。因此, 在类型中执行加法之前y转换为类型。表达式的结果类型是。因为它被分配给类型的变量,所以在添加之后执行另一个隐式转换。zuint16y + zuint16uint32

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数组和bytescalldata 切片可以显式转换为固定字节类型(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);
    }
}