一篇帶你看懂Go語言中的字符串拼接(小白入門)
在 Go 里:
字符串 string 是不可變的(你不能在原來的 string 上直接改)
所以 用 + / += 反復(fù)拼接,經(jīng)常會很慢(反復(fù)分配 + 復(fù)制)
為了快,Go 常用兩種方式:
- 用
[]byte+append拼 - 用
strings.Builder拼(寫法更像“拼字符串”,性能也好)
cap / Grow 都是在做同一件事:提前預(yù)留容量,減少擴(kuò)容拷貝
1. 為什么“拼字符串”會出問題?
你想要構(gòu)造一個(gè)輸出,比如:
"blue is sky the"
最直覺的寫法是:
ans := "" ans += "blue" ans += " " ans += "is"
看起來很合理對吧?
但 Go 的 string 有個(gè)關(guān)鍵特性:
Go 的 string 不可變(immutable)
你一旦創(chuàng)建了一個(gè) string,它里面的內(nèi)容不能“原地修改”。
所以 ans += "blue" 實(shí)際發(fā)生的是:
- 新開一塊內(nèi)存,長度 = oldLen + newLen
- 把舊的
ans復(fù)制進(jìn)去 - 再把
"blue"復(fù)制進(jìn)去 - 把
ans指向這塊新內(nèi)存
也就是說:每一次 += 都可能要“重新開數(shù)組 + 復(fù)制一遍舊內(nèi)容”
2. 這就是為什么+會慢:重復(fù)拷貝
舉個(gè)特別直觀的例子:
你要拼 3 次:
- 第 1 次:復(fù)制 0 個(gè)舊字符
- 第 2 次:復(fù)制 4 個(gè)舊字符("blue")
- 第 3 次:復(fù)制 7 個(gè)舊字符("blue is")
你會發(fā)現(xiàn):舊內(nèi)容一直在被反復(fù)復(fù)制。
拼得越多,復(fù)制越多,速度就越慢。
3. 那怎么快?核心思路:用“可變?nèi)萜?rdquo;先裝起來
既然 string 不可變,那我們先用一個(gè) 可變的容器 裝字符,最后一次性變成 string。
Go 最常用的可變?nèi)萜骶褪牵?/p>
[]byte(字節(jié)數(shù)組 / 可變)
你可以對它 append,它會自動增長:
ans := make([]byte, 0) ans = append(ans, 'b', 'l', 'u', 'e')
最后:
return string(ans)
這樣就避免了每次 += 的“重新分配 + 復(fù)制舊內(nèi)容”。
4. 這就引出了:len和cap是啥?
[]byte / []int 這些 slice,在 Go 里有兩個(gè)重要概念:
len:現(xiàn)在已經(jīng)用了多少cap:底層總共預(yù)留了多少空間(還能裝多少)
比如:
ans := make([]byte, 0, 10)
意思是:
len = 0(現(xiàn)在里面沒東西)cap = 10(底層數(shù)組先預(yù)留了 10 個(gè)位置)
為什么要 cap?
因?yàn)槿绻悴活A(yù)留,append 可能會這樣:
- 空間不夠 → 申請更大數(shù)組
- 把舊數(shù)組內(nèi)容復(fù)制過去
- 才能繼續(xù) append
所以:
cap 就是為了減少“擴(kuò)容 + 拷貝”的次數(shù)。
5. 超過 cap 會發(fā)生什么?
當(dāng)你 append 讓 len > cap:
- Go 會創(chuàng)建一個(gè)更大的新數(shù)組
- 把舊內(nèi)容復(fù)制到新數(shù)組
- slice 指向新數(shù)組
你看:又出現(xiàn)“復(fù)制舊內(nèi)容”了對吧?
所以我們才要 盡量提前預(yù)留 cap。
6. 這時(shí)候strings.Builder登場:更“像拼字符串”的工具
你用 []byte 拼字符串沒問題,但寫起來像在操作數(shù)組。 strings.Builder 是 Go 官方提供的:
專門用來高效拼接字符串的工具
你可以把它理解成:
“官方封裝好的[]byte + append”
它的用法是:
import "strings"
var b strings.Builder
b.WriteString("blue")
b.WriteByte(' ')
b.WriteString("sky")
result := b.String()
你可以把它理解成:
“內(nèi)部幫你維護(hù)了一個(gè) []byte 的拼接器”
你 WriteString/WriteByte,它內(nèi)部就在 append 到那個(gè) buffer 里。
最后 String() 一次性輸出。
7. 那Grow又是什么?它和cap的關(guān)系是什么?
現(xiàn)在關(guān)鍵來了:
Builder 內(nèi)部其實(shí)也需要容量,否則也會擴(kuò)容 + 拷貝。
所以它也需要“預(yù)留空間”。
這就是:
b.Grow(n)
意思是:
提前保證:接下來還能再寫 n 個(gè)字節(jié),不用擴(kuò)容
對應(yīng)到 slice 的感覺就是:
- slice:
make([]byte, 0, n)預(yù)留 cap - builder:
b.Grow(n)預(yù)留內(nèi)部 buffer 的 cap
所以它們關(guān)系是:
Grow 本質(zhì)上是在給 Builder 內(nèi)部的“隱藏 slice”擴(kuò) cap。
9. 小白怎么選
你現(xiàn)在階段記住這個(gè)就夠了:
簡單場景(拼得不多)
用 + 也行(比如 2~3 次拼接)
循環(huán)里大量拼接(比如這題、構(gòu)造大字符串)
優(yōu)先用:
strings.Builder(推薦,易讀)
或[]byte+append(你已經(jīng)在用)
追求性能時(shí)加一條:預(yù)留容量
ans := make([]byte, 0, len(s))b.Grow(len(s))
到此這篇關(guān)于一篇帶你看懂Go語言中的字符串拼接(小白入門)的文章就介紹到這了,更多相關(guān)Go字符串拼接內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang算法之田忌賽馬問題實(shí)現(xiàn)方法分析
這篇文章主要介紹了Golang算法之田忌賽馬問題實(shí)現(xiàn)方法,結(jié)合具體實(shí)例形式分析了基于Go語言的田忌賽馬問題原理與算法實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-02-02
Go語言字符串及strings和strconv包使用實(shí)例
字符串是工作中最常用的,值得我們專門的練習(xí)一下,下面這篇文章主要給大家介紹了關(guān)于Go語言字符串及strings和strconv包使用的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
詳解Golang實(shí)現(xiàn)http重定向https的方式
這篇文章主要介紹了詳解Golang實(shí)現(xiàn)http重定向https的方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
go-zero接入skywalking實(shí)現(xiàn)鏈路追蹤的詳細(xì)教程
SkyWalking是一個(gè)開源的服務(wù)追蹤系統(tǒng),它專注于分布式系統(tǒng)的可觀測性和服務(wù)性能分析,它的主要目標(biāo)是幫助開發(fā)者理解和優(yōu)化微服務(wù)架構(gòu)中的服務(wù)間交互情況,本文介紹了go-zero接入skywalking鏈路追蹤的詳細(xì)教程,需要的朋友可以參考下2024-08-08

