{"content":{"title":"应用二进制接口编码（ABI编码）","body":"我们需要在介绍下一个信息之前，再进行一个看似随机的插曲。\r\n\r\n但我希望你理解以下内容是什么\r\n\r\n- abi.encode\r\n\r\n- abi.decode\r\n\r\n- abi.encodeWithSignature\r\n\r\n\r\n为了说明它们的重要性，让我们创建另一个智能合约，打开“调试”下拉菜单，获取某些信息。\r\n\r\n![https://static.wixstatic.com/media/61a666_57ac790548bd46f293823e0574f3e152~mv2.png](https://img.learnblockchain.cn/2025/02/26/61a666_57ac790548bd46f293823e0574f3e152~mv2.png)\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n\r\n    function meaningOfLifeAndAllExistence()\r\n        public\r\n        pure\r\n        returns (uint256) {\r\n            return 42;\r\n    }\r\n}\r\n\r\n```\r\n\r\n当我们复制那个时，我们得到\r\n\r\n**0x92d62db5**\r\n\r\n这到底是什么？ 这是 “meaningOfLifeAndAllExistence()” 的 **函数签名**。我们稍后会学习这如何得出。\r\n\r\n每当你“调用”一个智能合约时，你实际上是发送一个附带一些数据的以太坊交易，以便智能合约知道要执行哪个函数。\r\n\r\n让我们从另一个角度来看信息。\r\n\r\n![https://static.wixstatic.com/media/61a666_38d5431035ee47bca02b56df9b3f92f7~mv2.png](<Base64-Image-Removed>)\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n\r\n    function meaningOfLifeAndAllExistence()\r\n        public\r\n        pure\r\n        returns (bytes memory) {\r\n            return msg.data;\r\n    }\r\n}\r\n\r\n```\r\n\r\n我们将返回类型更改为“bytes memory”（不必担心我们之前没有见过这个），并返回一个名为 msg.data 的变量（同样不必担心我们之前没有见过这个）。\r\n\r\n重要的是要注意到，我们得到的返回数据字节序列是相同的！\r\n\r\n那么发生了什么呢？\r\n\r\n当你调用智能合约中的一个函数时，你实际上并不是在进行一个“函数调用”，而是向合约发送数据，并附带关于应该执行哪个函数的信息。\r\n\r\n这样理解对吗？当你启动你的浏览器钱包并进行 ERC20 代币交易时，无法“远程调用” ERC20 合约的函数。函数调用只发生在同一执行上下文内。但是，将交易描述为函数是很方便的。但我们需要看清幕后发生的事情，以真正理解 Solidity。\r\n\r\n当你“调用智能合约”时，你是在向合约发送数据，并附带执行的指令。\r\n\r\n有许多数据编码方式，如 json、xml、protobuf 等。 **Solidity 和以太坊使用 ABI 编码**。\r\n\r\n我们在这里不深入讨论 ABI 的规范。但你需要知道的是，它总是看起来像一系列字节。\r\n\r\n函数被识别为四个字节的序列。我们最初的字节序列 **(0x92d62db5)** 有四个字节：92, d6, 2d, b5。\r\n\r\n请记住，一个字节是 8 位，并且 8 位的最大值可以是 255（2^8 - 1）。一个字节在十六进制中可以从 0x00 到 0xff 转换。将 0xff 转换为十进制，希望这会让你明白。\r\n\r\n当一个函数不带参数时，发送表示该函数的四个字节指示智能合约执行该函数。\r\n\r\n但是如果数据要带一个参数，它的样子会是什么？\r\n\r\n![https://static.wixstatic.com/media/61a666_2afb4e91b2f0423ba0d719a3d8b382ec~mv2.png](<Base64-Image-Removed>)\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n    function takeOneArg(uint256 x)\r\n        public\r\n        pure\r\n        returns (bytes memory) {\r\n            // 我们不会对 x 做任何事情\r\n            return msg.data;\r\n    }\r\n}\r\n\r\n```\r\n\r\n我们得到\r\n\r\n0xf8689fd30000000000000000000000000000000000000000000000000000000000000007\r\n\r\n这样的返回。f8689fd3 部分意味着调用函数 “takeOneArg”，而前面很多零的7则意味着传递数字7。\r\n\r\n如果我们必须手动进行这项操作，情况将会非常混乱。\r\n\r\n幸运的是，我们不需要。\r\n\r\n看看这个。\r\n\r\n![https://static.wixstatic.com/media/61a666_687ca50bc74449e28295e2641620d6c1~mv2.png](<Base64-Image-Removed>)\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n\r\n    function getEncoding(uint x)\r\n        public\r\n        pure\r\n        returns (bytes memory) {\r\n            return abi.encodeWithSignature(\"takeOneArg()\", x);\r\n    }\r\n\r\n    function takeOneArg(uint256 x)\r\n        public\r\n        pure\r\n        returns (bytes memory) {\r\n            return msg.data;\r\n    }\r\n}\r\n\r\n```\r\n\r\n现在我们不需要担心 ABI 编码的规范，让我们先适应它的使用。\r\n\r\n考虑以下示例。\r\n\r\n![https://static.wixstatic.com/media/61a666_ef35fbdaa086479aa76b7ce06edceb08~mv2.png](<Base64-Image-Removed>)\r\n\r\n```solidity\r\n\r\ncontract ExampleContract {\r\n\r\n    function encodingXY(uint x, uint256 y)\r\n        public\r\n        pure\r\n        returns (bytes memory) {\r\n            return abi.encode(x, y);\r\n    }\r\n\r\n    function getATuple(bytes memory encoding)\r\n        public\r\n        pure\r\n        returns (uint256, uint256) {\r\n            (uint256 x, uint256 y) = abi.decode(encoding,\r\n                (uint256, uint256));\r\n            return(x, y);\r\n    }\r\n}\r\n\r\n```\r\n\r\n请注意我们在使用“abi.encode”和“abi.decode”。 “withSignature” 部分是在涉及函数时使用，但在这里不是这种情况。\r\n\r\n在这个例子中，变量 x 和 y 被编码为\r\n\r\n0x0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000f\r\n\r\n十进制数字被转换为十六进制，因此“5”仍然是“5”，但“15”则变成了“f”。\r\n\r\n如果我们提前知道这是一对 uint256，我们可以使用上面截图的函数将其“解码”回一对数据。\r\n\r\n出现在 abi.decode 第二个参数的元组是解码数据的说明。如果在这里提供了错误的数据类型或错误的元组长度，你将得到错误的结果，或者代码将会撤销。\r\n\r\n**练习题**\r\n\r\n[编码](https://github.com/RareSkills/Solidity-Exercises/tree/main/Encoder)\r\n\r\n[解码器](https://github.com/RareSkills/Solidity-Exercises/tree/main/Decoder)\r\n\r\n### 了解更多信息 \r\n\r\n参见 [Solidity 练习营](https://learnblockchain.cn/openspace/1), 以了解更多关于智能合约开发和代币标准的信息。\r\n \r\n\r\n>- 原文链接： [rareskills.io/learn-soli...](https://www.rareskills.io/learn-solidity/abi)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/20722","address":null},"history":null,"timestamp":1740577361,"version":1}