Solidityメモ: 型変換(キャスト)
Solidityの型変換(キャスト)は少しややこしいので、整理してみました。
uintとint
範囲外であってもエラーにならずに変換されます。(例えば intの-1はuintの255になります。)
// int→uint (uintの範囲内) int8 i1 = 127; uint8 u1 = uint8(i1); // 127 // int→uint (uintの範囲外) int8 i2 = -1; uint8 u2 = uint8(i2); // 255 // uint→int (intの範囲内) uint8 u3 = 10; int8 i3 = int8(u3); // 10 // uint→int (intの範囲外) uint8 u4 = 200; int8 i4 = int8(u4); // -56
bytesとstring
bytesとstringは相互に変換可能です。
// string → bytes string memory s ="hello"; bytes memory b = bytes(s); // bytes → string bytes memory b = "world"; string memory s = string(b);
stringの長さを取得するときは、いったんbytesに変換してからlengthを使ったりします。(stringではlengthが使えないため)
string memory s = "hello"; uint len = bytes(s).length;
小さな型/大きな型への変換
uint16→uint8 のように同じuintで小さな型に変換する場合や、uint16→uint32のように大きな型に変換する場合は注意が必要です。
uintとbytesNでは挙動が違います。
// uintの場合 uint16 a = 0xabcd; uint8 b = uint8(a); // 0xcdになる (上位ビットが切り捨てられる) uint32 c = uint32(a); // 0x0000abcd (左がゼロで埋められる) // bytesNの場合 bytes2 a = 0xabcd; bytes1 b = bytes1(a); // 0xabになる (下位ビットが切り捨てられる) bytes4 c = bytes4(a); // 0xabcd0000 (右がゼロで埋められる)
これが原因で、キャスト途中の型によって結果が変わることがあります。 例えば、uint8からbytes4に変換する場合では以下のようになります。
uint8 a = 0xab; bytes4 b1 = bytes4(bytes1(a)); // bytes1を経由して変換すると結果は 0xab000000 bytes4 b2 = bytes4(uint32(a)); // uint32を経由して変換すると結果は 0x000000ab
intの場合
intもuintと同じように小さな型への変換では上位バイトが切り捨てられ、大きな型への変換では左がゼロで埋められます。
int16 a = -12345; // 0xcfc7 int8 b = int8(a); // -57 = 0xc7 int32 c = int32(a); // -12345 = 0x0000cfc7
bytesNとbytes
bytesからbytesNはキャストできます。挙動もbytesN同士のキャストと同じです。 (古い記事では1バイトずつコピーしている例がありますが、0.8.5からできるようになりました。)
bytes memory b = hex"123456"; bytes2 b2 = bytes2(b); // 0x1234 (下位ビットが切り捨て) bytes4 b4 = bytes4(b); // 0x12345600 (右がゼロで埋められる)
bytesNからbytesへのキャストはできないようなので、abi.encodePacked
を使いましょう。
bytes2 a = 0xabcd; bytes memory b = abi.encodePacked(a); // 0xabcd