跳转至

数据类型

智能合约中没有浮点数

布尔型

bool public b1 = true;
bool public b2 = false;

整型

  • 无符号整数,即正整数
// 长度:8~256
// uint等价于uint256,建议显性标识
uint8 public u2 = 20221209;  // 0 ~ 2**8-1
unit16  public u3  // 0 ~ 2**16-1
uint256 public u1 = 1;  // 0 ~ 2**256-1
  • 整数
// 同uint
int256 public i = -1;  // -2**255 ~ 2**255-1

type(int).min;  // 最小值
type(int).max;  // 最大值

字符串

string Text = "7c"

字节数组

// 长度:1~32
// bytes等价于bytes32
bytes32 public bt32 = "MiniSolidity";  // 存储为32字节:0x4d696e69536f6c6964697479...
bytes32 public bt32 = 0x4d696e69536f6c6964697479...;  // 也可以直接写为字节形式
bytes1 public bt = bt32[0];  // bt32的第一个字节:0x4d

地址类型

地址类型存储一个20字节的值

1Byte=8bit,每4位二进制可表示为1个十六进制数,所以一个字节可表示为2个十六进制数,即20字节用十六进制表示共40位,所以以太坊的钱包地址算上前缀0x,一共42位。

  • 普通地址
address public addr = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
  • 可转账地址
address payable public addr = payable(addr);

// 可转账地址有两个成员,方便查询余额和转账
addr.balance;  // 地址余额
addr.transfer(1)  // 合约向 addr 转账 1wei

数组

数组是存储相同数据类型元素的数据结构

  • 固定数组

data_type[size] array_name = <elements>;

uint256[3] public a1 = [1, 2, 3];
address[100] public a2;
bytes32[5] public a3;
  • 动态数组

data_type[] array_name = <elements>;

uint256[] public a1 = [1, 2, 3];
address[] public a2;
bytes32[] public a3;

// 数组的方法
uint[] public nums = [1, 2, 3];
uint public len = nums.length;  // 获取数组长度:3
// 需要在函数中操作
function demo() external {
    nums[2] = 33;  // 修改第3个元素:[1, 2, 33, 4],index溢出会报错
    nums.push(4);  // 向数组末尾插入元素:[1, 2, 3, 4]
    nums.push();  // 默认插入元素0:[1, 2, 3, 0]
    delete nums[2];  // 将第三个元素重置为0,就相当于删除,但不改变数组长度:[1, 2, 0, 4]
    nums.pop();  // 删除数组末尾元素,真删除,会改变数组长度:[1, 2, 3]
}
  • 在内存中创建数组
// 需要使用 memory 修饰
// 需要用 new 操作符
// 需要声明长度,且声明后不能改变,所以改变长度的方法都不能用,可以修改值
uint[] memory a = new uint[](5);
  • 返回数组中所有元素
// 需要加 memory
function returnArray() external view returns (uint[] memory) {
    return nums;
}

删除数组指定索引的元素,需要自定义函数

  • 通过移动位置,实现删除

Gas 消耗很大

uint[] public arr;

function remove(uint _index) public {
    require(_index < arr.length, "index out of bound");

    for (uint i = _index; i < arr.length - 1; i++) {
        arr[i] = arr[i + 1];
    }
    arr.pop();
}

function test() external {
    arr = [1, 2, 3, 4];

    remove(1);  // [1, 3, 4]
    assert(arr.length == 3);
    assert(arr[0] == 1);
    assert(arr[1] == 3);
    assert(arr[2] == 4);

    remove(2);  // [1, 3]
    assert(arr.length == 2);
    assert(arr[0] == 1);
    assert(arr[1] == 3);

    remove(0);  // [3]
    assert(arr.length == 1);
    assert(arr[0] == 3);

    remove(0);  // []
    assert(arr.length == 0);
}
  • 通过元素替换,实现删除

Gas消耗想对较少,但会改变数组顺序

uint[] public arr;

function remove(uint _index) public {
    require(_index < arr.length, "index out of bound");

    arr[_index] = arr[arr.length - 1];
    arr.pop();
}

function test() external {
    arr = [1, 2, 3, 4];

    remove(1);  // [1, 4, 3]
    assert(arr.length == 3);
    assert(arr[0] == 1);
    assert(arr[1] == 4);
    assert(arr[2] == 3);

    remove(2);  // [1, 4]
    assert(arr.length == 2);
    assert(arr[0] == 1);
    assert(arr[1] == 4);

    remove(0);  // [4]
    assert(arr.length == 1);
    assert(arr[0] == 4);

    remove(0);  // []
    assert(arr.length == 0);
}

结构体

// 定义结构体
struct Student{
    uint256 id;
    uint256 score; 
}

// 使用自定义的结构体声明一个变量
Student storage st;

st.id = 11;
st.score = 100;

映射

// 格式:mapping(KeyType => ValueType)
// 映射的KeyType不能使用自定义的结构体
// 映射的存储位置必须是storage
mapping(uint => address) public idToAddress;  // id映射到地址
mapping(address => address) public swapPair;  // 币对的映射,地址到地址

idToAddress[_Key] = _Value;  // 新增

枚举

主要用于为uint分配名称,使程序易于阅读和维护

enum ActionSet {Buy, Hold, Sell};  // 自定义枚举类型ActionSet
ActionSet action = ActionSet.Buy  // 创建ActionSet类型变量并赋值

// 枚举类型可以显式的和uint相互转换
uint(action);  // 0