热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang的字符串拼接

常用拼接方法字符串拼接在日常开发中是很常见的需求,目前有两种普遍做法:一种是直接用+来拼接s1:Hellos2:Worlds3:s1+s2

常用拼接方法

字符串拼接在日常开发中是很常见的需求,目前有两种普遍做法:

一种是直接用 += 来拼接

s1 := "Hello"
s2 := "World"
s3 := s1 + s2  // s3 == "HelloWorld"
s1 += s2       // s1 == "HelloWorld"

这是最常用也是最简单直观的方法,不过简单是有代价的,golang的字符串是不可变类型,也就是说每一次对字符串的“原地”修改都会重新生成一个string,再把数据复制进去,这样一来将会产生很可观的性能开销,稍后的性能测试中将会看到这一点。

 

第二种是使用bytes.Buffer

// bytes.Buffer的0值可以直接使用
var buff bytes.Buffer

// 向buff中写入字符/字符串
buff.Write([]byte("Hello"))
buff.WriteByte(' ')
buff.WriteString("World")

// String() 方法获得拼接的字符串
buff.String() // "Hello World"

这种方法用于需要大量进行字符串拼接操作的场合,性能要大大优于第一种方法。

 

不过使用bytes模块来操作string难免让人产生迷惑,所以在go1.10中新增了第三种方法:strings.Builder,官方鼓励尽量在string的拼接时使用Builder,byte拼接时使用Buffer

// strings.Builder的0值可以直接使用
var builder strings.Builder

// 向builder中写入字符/字符串
builder.Write([]byte("Hello"))
builder.WriteByte(' ')
builder.WriteString("World")

// String() 方法获得拼接的字符串
builder.String() // "Hello World"

从上面的代码中可以看到,strings.Builder和bytes.Buffer的操作几乎一样,不过strings.Builder仅仅实现了write类方法,而Buffer是可读可写的。

所以strings.Builder仅用于拼接/构建字符串

性能

除了是否易用外,另一条参考标准就是性能,得益于golang自带的测试工具,我们可以大致对比一下三种方案的性能。

测试使用从26个大写和小写字母10个数字以及5个常用符号共67字符中随机取10个组成string或[]byte,再由Buffer和Builder进行拼接。

先上测试结果

go test -bench=. -benchmem

 

下面是测试代码

// BenchmarkSpliceAddString10 测试使用 += 拼接N次长度为10的字符串
func BenchmarkSpliceAddString10(b *testing.B) {
    s := ""
    for i := 0; i  {
        s += GenRandString(10)
    }
}

// BenchmarkSpliceBuilderString10 测试使用strings.Builder拼接N次长度为10的字符串
func BenchmarkSpliceBuilderString10(b *testing.B) {
    var builder strings.Builder
    for i := 0; i  {
        builder.WriteString(GenRandString(10))
    }
}

// BenchmarkSpliceBufferString10 测试使用bytes.Buffer拼接N次长度为10的字符串
func BenchmarkSpliceBufferString10(b *testing.B) {
    var buff bytes.Buffer
    for i := 0; i  {
        buff.WriteString(GenRandString(10))
    }
}

// BenchmarkSpliceBufferByte10 测试使用bytes.Buffer拼接N次长度为10的[]byte
func BenchmarkSpliceBufferByte10(b *testing.B) {
    var buff bytes.Buffer
    for i := 0; i  {
        buff.Write(GenRandBytes(10))
    }
}

// BenchmarkSpliceBuilderByte10 测试使用string.Builder拼接N次长度为10的[]byte
func BenchmarkSpliceBuilderByte10(b *testing.B) {
    var builder strings.Builder
    for i := 0; i  {
        builder.Write(GenRandBytes(10))
    }
}

这是生成供拼接使用的随机字符串的代码(这里仍然使用了bytes.Buffer,推荐使用新的strings.Builder)

const (
    data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890,.-=/"
)

func init() {
    rand.Seed(time.Now().Unix()) // 设置随机种子
}

// GenRandString 生成n个随机字符的string
func GenRandString(n int) string {
    max := len(data)
    var buf bytes.Buffer
    for i := 0; i  {
        buf.WriteByte(data[rand.Intn(max)])
    }

    return buf.String()
}

// GenRandBytes 生成n个随机字符的[]byte
func GenRandBytes(n int) []byte {
    max := len(data)
    buf := make([]byte, n)
    for i := 0; i  {
        buf[i] = data[rand.Intn(max)]
    }

    return buf
}

 

使用 += 的方法性能是最慢的,性能和其他两种差了好几个数量级。

Buffer和Builder性能相差无几,Builder在内存的使用上要略优于Buffer

结论

strings.Builder在golang 1.10才引入标准库的,所以 version <= 1.9 的时候对于大量字符串的拼接操作推荐bytes.Buffer

如果你正在使用1.10+,那么建议使用strings.Builder,不仅是更好的性能,也是为了能使代码更清晰。

当然,对于简单的拼接,+= 就足够了


推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了PHP常量的定义和使用方法,包括常量的命名规则、大小写敏感性、全局范围和标量数据的限制。同时还提到了应尽量避免定义resource常量,并给出了使用define()函数定义常量的示例。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • 【技术分享】一个 ELF 蠕虫分析
    【技术分享】一个 ELF 蠕虫分析 ... [详细]
  • golang 解析磁力链为 torrent 相关的信息
    其实通过http请求已经获得了种子的信息了,但是传播存储种子好像是违法的,所以就存储些描述信息吧。之前python跑的太慢了。这个go并发不知道写的有没有问题?!packag ... [详细]
  • 看到平台银行对接方案写的demo确实还不错记个笔记互相学习学习packageapiimport(cryptotlsnetnethttpstringssynct ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
贾春雨-cherry
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有