字节和字符串

本章学习 Solidity 字节和字符串的定义语法和使用方法。

视频:Bilibili  |  Youtube
推特:@Hita_DAO    Discord:HitaDAO

在学习字符串 类型之前,我们要首先掌握 字节型 。字节型 也是 Solidity 语言中重要的数据类型。

字节型 用于表示特定长度的字节序列,分为 固定长度字节型 和 动态长度字节型 两种类型。

字节型 本质上是一个字节数组。Solidity 为了方便使用,把它单独定义为一种数据类型。

比如,在智能合约中经常出现的哈希值、数据签名等数据,都会使用 字节型 来定义。

1. 固定长度字节型

固定长度字节型 按照长度分为 32 种小类,使用 bytes1、bytes2、bytes3 直到 bytes32 表示,每种类型代表不同长度的字节序列,其中的 bytes32 使用最为普遍。

固定长度字节型 的变量声明如下:

bytes1 myBytes1 = 0x12;  // 单个字节
bytes2 myBytes2 = 0x1234;  // 两个字节
bytes32 myBytes32 = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef; // 32个字节

对于 固定长度字节型 的变量的使用方法,与 固定长度数组 基本相同。

我们使用下面的智能合约作为范例,来说明它的用法。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StaticBytes {
    function staticBytes() external pure returns (uint256, bytes2, bytes1) {
        bytes2 myBytes = 0x1212; // 声明固定长度字节型变量
        myBytes = 0x3456; // 设置整个字节型变量的值
        bytes1 b = myBytes[0]; // 读取单个字节的值
        // myBytes[0] = 0x78; // 不允许设置单个字节的值
        return (myBytes.length, myBytes, b);// .length 取字符串的长度
    }
}

2. 动态长度字节型

动态长度字节型 可以存储任意长度的字节序列,它使用关键字 bytes 来声明,在声明变量时,需要指定其长度或初始化值。

动态长度字节型 的变量声明如下:

bytes myBytes = new bytes(10);  // 声明一个长度为 10 的动态长度字节变量
bytes myBytes = "Hello";  // 声明一个动态长度字节变量,并初始化为 "Hello"
bytes myBytes = hex"1234";  // 声明一个动态长度字节变量,并初始化为十六进制 0x1234

对于 动态长度字节型 的变量的使用方法,与 动态长度数组 基本相同。

我们使用下面的智能合约作为范例,来展示其用法。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DynamicBytes {
    function dynamicBytes() external pure returns (uint256, bytes memory) {
        bytes memory myBytes = new bytes(2); // 创建动态长度字节型变量
        myBytes[0] = 0x12; // 设置单个字节的值
        myBytes[1] = 0x34; 
        return (myBytes.length, myBytes);// .length 取字符串的长度
    }
}

3. 字符串

在 Solidity 中,字符串 是用来存储文本数据的类型。

字符串的值使用双引号 (") 或单引号 (') 包裹,类型用 string 表示。

string public myString = "Hello World";

字符串与固定长度的字节数组非常类似,它的值在声明之后就不可变了。

如果想要对字符串中包含的字符进行操作,通常会将它转换为 bytes 类型。

Solidity 提供了字节数组 bytes 与字符串 string 之间的内置转换。

3.1 bytes 转换 string

可以使用 string() 函数将 bytes 显式转换为字符串 string。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StringConvertor {
    function bytesToString() external pure returns (string memory) {
        bytes memory myBytes = new bytes(2);
        myBytes[0] = 'o';
        myBytes[1] = 'k';
        return string(myBytes); // 返回字符串 ok
    }
}

运行上述合约,调用 bytesToString 函数后,返回字符串 "ok"。

3.2 string 转换 bytes

可以使用 bytes() 函数将 string 显式转换为字节数组 bytes。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract BytesConvertor {
    function stringToBytes() external pure returns(bytes memory) {
        string memory myString = "Hello World";
        return bytes(myString); // 返回字节数组
    }
}

运行上述合约,调用 stringToBytes 函数后,返回字节数组 "0x48656c6c6f20576f726c64"。

3.3 获得字符串长度

字符串 并没有直接获得长度的函数,需要先转换为 bytes,再求其长度。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StringLen {
    function len() external pure returns (uint) {
        string memory myString = "Hello World";
        return bytes(myString).length; 
    }
}

3.4 支持 unicode 编码

如果字符串中含有 unicode 编码的字符,比如表情符号或者中文,那么就需要在赋值的时候进行显示声明,否则会报错。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract StringUnicode {
    function greet() external pure returns (string memory) {
        return unicode"Hello 泽宾";
    }
}