一篇带你看懂Go语言中的字符串拼接(小白入门)

 更新时间:2026年02月09日 09:41:26   作者:却尘  
这篇文章主要为大家详细介绍了Go语言中进行字符串拼接的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

在 Go 里:

字符串 string 是不可变的(你不能在原来的 string 上直接改)

所以 + / += 反复拼接,经常会很慢(反复分配 + 复制)

为了快,Go 常用两种方式:

  • []byte + append
  • strings.Builder 拼(写法更像“拼字符串”,性能也好)

cap / Grow 都是在做同一件事:提前预留容量,减少扩容拷贝

1. 为什么“拼字符串”会出问题?

你想要构造一个输出,比如:

"blue is sky the"

最直觉的写法是:

ans := ""
ans += "blue"
ans += " "
ans += "is"

看起来很合理对吧?

但 Go 的 string 有个关键特性:

Go 的 string 不可变(immutable)

你一旦创建了一个 string,它里面的内容不能“原地修改”。

所以 ans += "blue" 实际发生的是:

  • 新开一块内存,长度 = oldLen + newLen
  • 把旧的 ans 复制进去
  • 再把 "blue" 复制进去
  • ans 指向这块新内存

也就是说:每一次 += 都可能要“重新开数组 + 复制一遍旧内容”

2. 这就是为什么+会慢:重复拷贝

举个特别直观的例子:

你要拼 3 次:

  • 第 1 次:复制 0 个旧字符
  • 第 2 次:复制 4 个旧字符("blue")
  • 第 3 次:复制 7 个旧字符("blue is")

你会发现:旧内容一直在被反复复制。

拼得越多,复制越多,速度就越慢。

3. 那怎么快?核心思路:用“可变容器”先装起来

既然 string 不可变,那我们先用一个 可变的容器 装字符,最后一次性变成 string。

Go 最常用的可变容器就是:

[]byte(字节数组 / 可变)

你可以对它 append,它会自动增长:

ans := make([]byte, 0)
ans = append(ans, 'b', 'l', 'u', 'e')

最后:

return string(ans)

这样就避免了每次 += 的“重新分配 + 复制旧内容”。

4. 这就引出了:len和cap是啥?

[]byte / []int 这些 slice,在 Go 里有两个重要概念:

  • len:现在已经用了多少
  • cap:底层总共预留了多少空间(还能装多少)

比如:

ans := make([]byte, 0, 10)

意思是:

  • len = 0(现在里面没东西)
  • cap = 10(底层数组先预留了 10 个位置)

为什么要 cap?

因为如果你不预留,append 可能会这样:

  • 空间不够 → 申请更大数组
  • 把旧数组内容复制过去
  • 才能继续 append

所以:

cap 就是为了减少“扩容 + 拷贝”的次数。

5. 超过 cap 会发生什么?

当你 append 让 len > cap

  • Go 会创建一个更大的新数组
  • 把旧内容复制到新数组
  • slice 指向新数组

你看:又出现“复制旧内容”了对吧?

所以我们才要 尽量提前预留 cap

6. 这时候strings.Builder登场:更“像拼字符串”的工具

你用 []byte 拼字符串没问题,但写起来像在操作数组。 strings.Builder 是 Go 官方提供的:

专门用来高效拼接字符串的工具

你可以把它理解成:

“官方封装好的[]byte + append”

它的用法是:

import "strings"

var b strings.Builder
b.WriteString("blue")
b.WriteByte(' ')
b.WriteString("sky")
result := b.String()

你可以把它理解成:

“内部帮你维护了一个 []byte 的拼接器”

WriteString/WriteByte,它内部就在 append 到那个 buffer 里。

最后 String() 一次性输出。

7. 那Grow又是什么?它和cap的关系是什么?

现在关键来了:

Builder 内部其实也需要容量,否则也会扩容 + 拷贝。

所以它也需要“预留空间”。

这就是:

b.Grow(n)

意思是:

提前保证:接下来还能再写 n 个字节,不用扩容

对应到 slice 的感觉就是:

  • slice:make([]byte, 0, n) 预留 cap
  • builder:b.Grow(n) 预留内部 buffer 的 cap

所以它们关系是:

Grow 本质上是在给 Builder 内部的“隐藏 slice”扩 cap

9. 小白怎么选

你现在阶段记住这个就够了:

简单场景(拼得不多)

+ 也行(比如 2~3 次拼接)

循环里大量拼接(比如这题、构造大字符串)

优先用:

  • strings.Builder(推荐,易读)
  • []byte + append(你已经在用)

追求性能时加一条:预留容量

  • ans := make([]byte, 0, len(s))
  • b.Grow(len(s))

到此这篇关于一篇带你看懂Go语言中的字符串拼接(小白入门)的文章就介绍到这了,更多相关Go字符串拼接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言学习教程之声明语法(译)

    Go语言学习教程之声明语法(译)

    Golang 就是类C的语法,下面这篇文章主要给大家介绍了关于Go语言学习教程之声明语法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-11-11
  • Go语言调用DeepSeek API实现流式输出和对话

    Go语言调用DeepSeek API实现流式输出和对话

    DeepSeek是一个强大的AI模型服务平台,本文将详细介绍如何使用Go语言调用DeepSeek API实现流式输出和对话功能,感兴趣的小伙伴可以了解一下
    2025-02-02
  • golang http 连接超时和传输超时的例子

    golang http 连接超时和传输超时的例子

    今天小编就为大家分享一篇golang http 连接超时和传输超时的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • 浅谈Go语言中高效并发模式

    浅谈Go语言中高效并发模式

    Go语言并发编程提供了丰富的模式,包括基础Goroutine、Channel和Select机制,以及多种高级并发模式,本文就来详细的介绍一下,感兴趣的可以了解一下
    2025-10-10
  • golang中validator包的使用教程

    golang中validator包的使用教程

    Validator 实际上是一个验证工具,属于 golang 的第三方包,这个包中使用了各种反射技巧来提供了各种校验和约束数据的方式方法,下面就跟随小编一起来学习一下validator包的使用吧
    2023-09-09
  • 学会提升Go语言编码效率技巧拒绝加班!

    学会提升Go语言编码效率技巧拒绝加班!

    这篇文章主要为大家介绍了Go语言编码效率提升技巧详解,学会了从此拒绝加班,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • PHP结构型模式之组合模式

    PHP结构型模式之组合模式

    这篇文章主要介绍了PHP组合模式Composite Pattern优点与实现,组合模式是一种结构型模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组合能让客户端以一致的方式处理个别对象和对象组合
    2023-04-04
  • Go自定义数据序列化的流程详解

    Go自定义数据序列化的流程详解

    在Go语言中,自定义数据的序列化是一个常见的需求,本文将深入探讨 Go 语言中自定义数据序列化的流程,包括关键概念、技巧和最佳实践,旨在帮助开发者更高效地进行数据序列化工作,需要的朋友可以参考下
    2024-06-06
  • Go语言题解LeetCode561数组拆分

    Go语言题解LeetCode561数组拆分

    这篇文章主要为大家介绍了Go语言题解LeetCode561数组拆分示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Go语言中gPRC的使用

    Go语言中gPRC的使用

    本文主要介绍了Go语言中gPRC的使用,包括Protobuf定义服务接口、HTTP/2协议与性能优势,以及流模式和发布-订阅系统的实现,具有一定的参考价值,感兴趣的可以了解一下
    2025-07-07

最新评论