跨平台数据类型指南
由于 Solidity 和 JavaScript/TypeScript 的设计目标和应用场景不同,某些类型的对应关系可能不完全直接,需要进行一些转换或使用特定的库。
Solidity 类型 | Dart 类型 | JavaScript/TypeScript 类型 | 备注 |
---|---|---|---|
bool |
bool |
boolean |
直接对应。 |
uint8 , uint16 , uint32 , uint64 , uint256
|
BigInt |
number (如果数值较小) / string (推荐) / BigInt (ES2020+) |
JavaScript 的 number 类型只能安全地表示 -2^53 到 2^53 之间的整数。对于 Solidity 中的大整数,推荐使用字符串表示,或者使用 ES2020 引入的 BigInt 类型。需要注意的是,BigInt 在一些旧版本的浏览器中可能不支持。 |
int8 , int16 , int32 , int64 , int256
|
BigInt |
number (如果数值较小) / string (推荐) / BigInt (ES2020+) |
同样,对于 Solidity 中的大整数,推荐使用字符串表示,或者使用 ES2020 引入的 BigInt 类型。 |
address |
EthereumAddress (来自 web3dart 包) |
string |
以太坊地址通常表示为 16 进制字符串。可以使用 ethers 或 web3.js 等库提供的工具函数来验证地址的有效性。 |
string |
String |
string |
直接对应。 |
bytes1 , bytes2 , ..., bytes32
|
Uint8List |
string / number[]
|
可以使用 16 进制字符串表示,或者使用 Uint8Array (number[] ) 表示字节数组。 |
bytes |
Uint8List |
string / number[]
|
可以使用 16 进制字符串表示,或者使用 Uint8Array (number[] ) 表示字节数组。 |
fixed , ufixed
|
double (不推荐), 或者使用自定义类型和 BigInt
|
number / string / 自定义类型 |
JavaScript 没有直接对应的定点数类型。可以使用 number 类型近似表示,但会有精度损失。推荐使用字符串表示,或者使用第三方库来处理定点数。 |
enum |
enum (Dart) |
string (推荐) / number / enum (TypeScript) |
在 TypeScript 中,可以使用 enum 关键字定义枚举类型。如果需要在 JavaScript 中使用,可以使用字符串或数字来表示枚举值。 使用字符串可以提高代码的可读性。 |
mapping |
不直接对应 | JavaScript 对象 ({ [key: string]: value } ) / Map
|
Solidity 中的 mapping 类似于 JavaScript 中的对象或 Map 。你需要根据 key 来读取 mapping 的值。 在与智能合约交互时,通常需要编写合约函数来读取 mapping 的值。 |
array (fixed size) |
List<Type> |
Type[] |
例如 uint256[3] 对应 string[] (如果使用字符串表示大整数)。 |
array (dynamic size) |
List<Type> |
Type[] |
例如 uint256[] 对应 string[] (如果使用字符串表示大整数)。 |
注意:
- 在 JavaScript/TypeScript 中处理 Solidity 的数据类型时,需要考虑类型转换和数据格式化的问题。
- 可以使用
ethers
或web3.js
等库来简化与智能合约的交互。 - 对于复杂的数据结构,可能需要自定义类型或使用第三方库来处理。
-
BigInt
是 ES2020 引入的新特性,需要确保你的运行环境支持。
// 案例用 Solidity 0.8+ 版本编写
// = 1.智能合约基础结构 =
contract SimpleContract {
// 状态变量(永久存储在链上)
address public owner;
uint256 public count;
// 构造函数(只在部署时执行一次)
constructor() {
owner = msg.sender;
count = 0;
}
}
// = 2.数据类型与变量操作 =
contract DataTypes {
// 值类型
uint8 public smallNumber = 255; // 无符号8位整数
address public myAddress = 0x123...; // 以太坊地址
// 引用类型
struct Person {
string name;
uint age;
}
Person[] public people; // 动态结构体数组
// 映射类型
mapping(address => uint) public balances;
}
// = 3.函数与可见性 =
contract Functions {
uint private secretNumber = 42; // 私有变量
// public: 外部和内部均可调用
function add(uint a, uint b) public pure returns(uint) {
return a + b;
}
// external: 只能从外部调用
function deposit() external payable {
require(msg.value > 0, "Need ETH");
}
}
// = 4.事件与日志 =
contract EventDemo {
// 声明转账事件(链下可监听)
event Transfer(address indexed from, address to, uint amount);
function sendCoin(address to, uint amount) public {
emit Transfer(msg.sender, to, amount); // 触发事件
}
}
// = 5.错误处理 =
contract ErrorHandling {
function withdraw(uint amount) public {
require(amount <= 100, "Exceed max limit"); // 条件检查
if (amount == 0) {
revert("Amount cannot be zero"); // 主动回滚
}
// ...逻辑代码
}
}
// = 6.继承与接口 =
interface IERC20 {
function transfer(address to, uint amount) external;
}
contract MyToken is IERC20 { // 实现接口
function transfer(address to, uint amount) external override {
// 转账逻辑...
}
}
// = 7.支付处理 =
contract PaymentDemo {
// payable修饰符允许接收ETH
function buyItem() external payable {
require(msg.value == 1 ether, "Need 1 ETH");
}
// 提取合约余额
function withdraw() external {
payable(msg.sender).transfer(address(this).balance);
}
}
// = 8.存储位置示例 =
contract StorageExample {
struct User {
string name;
uint score;
}
User[] public users; // storage类型
function addUser(string memory name) public { // memory临时存储
users.push(User(name, 0));
}
}
// = 9.安全模式示例 =
contract ReentrancyGuard {
// 防重入锁
bool private locked;
modifier nonReentrant() {
require(!locked, "Operation locked");
locked = true;
_;
locked = false;
}
function safeWithdraw() public nonReentrant {
// 提款安全逻辑
}
}