字符串类型
关键字: string
字符串是UTF-8编码的字节序列,因此它们可以包含任何UTF-8字符。string类型在Solidity中是动态大小的,这意味着它们可以存储任意长度的字符串,但这也意味着处理字符串通常比处理固定大小的数据类型更昂贵,特别是在需要存储到Ethereum区块链上时。
使用方式
声明和初始化字符串变量的基本语法如下: 基本上和大多数语言一样
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract StringExample {
// 定义字符串
string public greeting = "Hello, World!";
// 补充一下代码注释部分
// 这是一个单行注释
// uint256 public count = 10;
uint256 public count = 10; // 这也是单行注释,位于代码行的末尾
/*
这是一个多行注释它
可以跨越多行
你可以用它来临时注释掉一段代码
uint256 public count = 10;
*/
}
字符串操作
Solidity本身对字符串的内置操作非常有限
比如字符串拼接,下表总结了不同编程语言中字符串拼接的常用方法:
语言 | 拼接方法 |
Python |
|
JavaScript |
|
Java |
|
C# |
|
Ruby |
|
Swift |
|
Go |
|
Kotlin |
|
solidity | 使用abi.encodePacked(str1, str2) 或 bytes类型操作,新版可以使用string.concat |
可以例如,最简单的字符串操作,将 2 个字符串合并,在Solidity 中都没办法直接通过+号合并,甚至你都不能直接获取字符串的长度。
如果需要进行这些操作,通常需要将字符串转换为bytes类型,或者在合约外部处理字符串逻辑。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 字符串例子
contract StringConcatenation {
// 示例字符串
string public exampleString = "Hello, World!";
string public exampleString1 = unicode"Hello, World!哈哈";
// 获取字符串长度的函数
// 首先将exampleString转换为bytes类型,这是通过简单地使用bytes(exampleString)实现的。
// 然后,它返回这个字节序列的.length属性,这就是原始字符串的长度。
// 注意这个计算,不一定就是准确的,对于中文来说
// 因为这种方法计算的是字符串的字节长度,而不是字符长度。
// 对于纯ASCII字符串(如示例中的"Hello, World!"),字节长度与字符长度相同。
// 但是,对于包含多字节字符的UTF-8字符串,字节长度可能会大于字符数量。
// 例如,一个包含某些表情符号或其他非ASCII字符的字符串可能会占用更多的字节。
function getStringLength() public view returns (uint256) {
// 将字符串转换为bytes类型,然后获取其长度
// 返回13
// return bytes(exampleString).length;
// 返回20 , 实际15
return bytes(exampleString1).length;
}
// 拼接两个字符串
// 使用abi.encodePacked来拼接两个字符串。
// abi.encodePacked可以接受任意数量的参数,并将它们紧密打包成一个字节序列。
// 然后,我们通过string()构造函数将结果转换回字符串。
// 使用string.concat也可以连接字符串
// 但是需要在Solidity 0.8.11及更高版本中,
// 以上版本引入了全局string库,其中包含了一个concat函数,
// 可以用来连接字符串。这是一个内置的、gas效率更高的方法来连接字符串。
// 目前我们还是0.8.0版本没有这个函数
function concatenate(string memory str1, string memory str2) public pure returns (string memory) {
return string(abi.encodePacked(str1, str2));
}
// 比较两个字符串是否相等
// 如果散列值相同,那么可以认为字符串相等(尽管理论上存在极小的碰撞概率)
function isEqual(string memory str1, string memory str2) public pure returns (bool) {
return keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2));
}
}
由于字符串是动态大小的数据类型,处理它们(比如拼接、切片或比较)通常比处理固定大小的数据类型更复杂和更昂贵。
例如: 字符串拼接需要创建一个新的动态数组来存储结果,这个过程涉及到内存分配和多次复制操作,每一步都会消耗gas。
通过以上例子可见在寸土寸金的以太坊网络,处理字符串是多么昂贵
优化建议
- 对于复杂的字符串操作,考虑在应用层(比如使用JavaScript、Python等)而不是在智能合约中处理。
- 对于不需要永久存储在区块链上的数据,使用memory或calldata类型来减少存储成本。
- 在Ethereum智能合约中处理字符串可能会消耗较多的gas,特别是当字符串作为函数参数或者需要在区块链上存储时。
总的来说,虽然字符串操作在Solidity中是可行的,但应该谨慎使用,以避免不必要的高成本。
PS: string 并不是值类型, 他是属于数组后面数组哪里我们也会在讲、
放在这里讲,是为了认识 solidity 与其他语言的区别, 方便更好的学习
注意事项
- 在Ethereum智能合约中处理字符串可能会消耗较多的gas,特别是当字符串作为函数参数或者需要在区块链上存储时。
- Solidity中的字符串是不可变的,这意味着一旦字符串被创建,你就不能修改它的内容。如果需要修改字符串,通常的做法是创建一个新的字符串变量。
- 对于复杂的字符串操作,考虑在应用层(比如使用JavaScript、Python等)而不是在智能合约中处理。
通过了解这些基本概念和限制,你可以更有效地在Solidity合约中使用字符串类型。