字节和字符串

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

视频Bilibili  |  Youtube
官网binschool.app
推特@BinSchool    DiscordBinDAO   微信:bkra50 

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

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

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

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

1. 固定长度字节型

固定长度字节型 按照长度分为 32 种小类,使用 bytes1bytes2bytes3 直到 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 泽宾";
    }
}