版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第GoLangstrings.Builder底層實(shí)現(xiàn)方法詳解目錄1.strings.Builder結(jié)構(gòu)體1.1strings.Builder結(jié)構(gòu)體1.2Write方法1.3WriteByte方法1.4WriteRune方法1.5.WriteString方法1.6String方法1.7Len方法1.8Cap方法1.9Reset方法1.10Grow方法1.11grow方法1.12copyCheck方法2.strings.Builder介紹3.存儲原理4.拷貝問題5.不能與nil作比較6.Grow深入7.不支持并行讀寫
1.strings.Builder結(jié)構(gòu)體
1.1strings.Builder結(jié)構(gòu)體
//ABuilderisusedtoefficientlybuildastringusingWritemethods.
//Itminimizesmemorycopying.Thezerovalueisreadytouse.
//Donotcopyanon-zeroBuilder.
typeBuilderstruct{
addr*Builder//ofreceiver,todetectcopiesbyvalue
buf[]byte
1.2Write方法
//Writeappendsthecontentsofptob'sbuffer.
//Writealwaysreturnslen(p),nil.
func(b*Builder)Write(p[]byte)(int,error){
b.copyCheck()
b.buf=append(b.buf,p...)
returnlen(p),nil
1.3WriteByte方法
//WriteByteappendsthebytectob'sbuffer.
//Thereturnederrorisalwaysnil.
func(b*Builder)WriteByte(cbyte)error{
b.copyCheck()
b.buf=append(b.buf,c)
returnnil
1.4WriteRune方法
//WriteRuneappendstheUTF-8encodingofUnicodecodepointrtob'sbuffer.
//Itreturnsthelengthofrandanilerror.
func(b*Builder)WriteRune(rrune)(int,error){
b.copyCheck()
//Compareasuint32tocorrectlyhandlenegativerunes.
ifuint32(r)utf8.RuneSelf{
b.buf=append(b.buf,byte(r))
return1,nil
l:=len(b.buf)
ifcap(b.buf)-lutf8.UTFMax{
b.grow(utf8.UTFMax)
n:=utf8.EncodeRune(b.buf[l:l+utf8.UTFMax],r)
b.buf=b.buf[:l+n]
returnn,nil
1.5.WriteString方法
//WriteStringappendsthecontentsofstob'sbuffer.
//Itreturnsthelengthofsandanilerror.
func(b*Builder)WriteString(sstring)(int,error){
b.copyCheck()
b.buf=append(b.buf,s...)
returnlen(s),nil
1.6String方法
和bytes.Buffer一樣,strings.Builder也支持使用String()來獲取最終的字符串結(jié)果。為了節(jié)省內(nèi)存分配,它通過使用指針技術(shù)將內(nèi)部的bufferbytes轉(zhuǎn)換為字符串。所以String()方法在轉(zhuǎn)換的時(shí)候節(jié)省了時(shí)間和空間。
//Stringreturnstheaccumulatedstring.
func(b*Builder)String()string{
return*(*string)(unsafe.Pointer(b.buf))
1.7Len方法
//Lenreturnsthenumberofaccumulatedbytes;b.Len()==len(b.String()).
func(b*Builder)Len()int{returnlen(b.buf)}
1.8Cap方法
//Capreturnsthecapacityofthebuilder'sunderlyingbyteslice.Itisthe
//totalspaceallocatedforthestringbeingbuiltandincludesanybytes
//alreadywritten.
func(b*Builder)Cap()int{returncap(b.buf)}
1.9Reset方法
//ResetresetstheBuildertobeempty.
func(b*Builder)Reset(){
b.addr=nil
b.buf=nil
1.10Grow方法
//Growgrowsb'scapacity,ifnecessary,toguaranteespacefor
//anothernbytes.AfterGrow(n),atleastnbytescanbewrittentob
//withoutanotherallocation.Ifnisnegative,Growpanics.
func(b*Builder)Grow(nint){
b.copyCheck()
ifn0{
panic("strings.Builder.Grow:negativecount")
ifcap(b.buf)-len(b.buf)n{
b.grow(n)
1.11grow方法
//growcopiesthebuffertoanew,largerbuffersothatthereareatleastn
//bytesofcapacitybeyondlen(b.buf).
func(b*Builder)grow(nint){
buf:=make([]byte,len(b.buf),2*cap(b.buf)+n)
copy(buf,b.buf)
b.buf=buf
1.12copyCheck方法
func(b*Builder)copyCheck(){
ifb.addr==nil{
//ThishackworksaroundafailingofGo'sescapeanalysis
//thatwascausingbtoescapeandbeheapallocated.
//Seeissue23382.
//TODO:onceissue7921isfixed,thisshouldberevertedto
//just"b.addr=b".
b.addr=(*Builder)(noescape(unsafe.Pointer(b)))
}elseifb.addr!=b{
panic("strings:illegaluseofnon-zeroBuildercopiedbyvalue")
2.strings.Builder介紹
與bytes.Buffer類似,strings.Builder也支持4類方法將數(shù)據(jù)寫入builder中。
func(b*Builder)Write(p[]byte)(int,error)
func(b*Builder)WriteByte(cbyte)error
func(b*Builder)WriteRune(rrune)(int,error)
func(b*Builder)WriteString(sstring)(int,error)
有了它們,用戶可以根據(jù)輸入數(shù)據(jù)的不同類型(byte數(shù)組,byte,rune或者string),選擇對應(yīng)的寫入方法。
3.存儲原理
根據(jù)用法說明,我們通過調(diào)用string.Builder的寫入方法來寫入內(nèi)容,然后通過調(diào)用String()方法來獲取拼接的字符串。那么string.Builder是如何組織這些內(nèi)容的呢?
通過slice,string.Builder通過使用一個(gè)內(nèi)部的slice來存儲數(shù)據(jù)片段。當(dāng)開發(fā)者調(diào)用寫入方法的時(shí)候,數(shù)據(jù)實(shí)際上是被追加(append)到了其內(nèi)部的slice上。
4.拷貝問題
strings.Builder不推薦被拷貝。當(dāng)你試圖拷貝strings.Builder并寫入的時(shí)候,你的程序就會崩潰。
你已經(jīng)知道,strings.Builder內(nèi)部通過slice來保存和管理內(nèi)容。slice內(nèi)部則是通過一個(gè)指針指向?qū)嶋H保存內(nèi)容的數(shù)組。當(dāng)我們拷貝了builder以后,同樣也拷貝了其slice的指針。但是它仍然指向同一個(gè)舊的數(shù)組。當(dāng)你對源builder或者拷貝后的builder寫入的時(shí)候,問題就產(chǎn)生了。另一個(gè)builder指向的數(shù)組內(nèi)容也被改變了。這就是為什么strings.Builder不允許拷貝的原因。
funcmain(){
varb1strings.Builder
b1.WriteString("ABC")
b2:=b1
b2.WriteString("DEF")//出錯(cuò)在這一行,panic:strings:illegaluseofnon-zeroBuildercopiedbyvalue
funcmain(){
varb1strings.Builder
b1.WriteString("ABC")
b2:=b1
fmt.Println(b2.String())//ABC
funcmain(){
varb1strings.Builder
b1.WriteString("ABC")
b2:=b1
fmt.Println(b1.String())//輸出:ABC
fmt.Println(b2.String())//輸出:ABC
b1.WriteString("DEF")
fmt.Println(b1.String())//輸出:ABCDEF
fmt.Println(b2.String())//輸出:ABC
但對于一個(gè)未寫入任何東西的空內(nèi)容builder則是個(gè)例外。我們可以拷貝空內(nèi)容的builder而不報(bào)錯(cuò)。
funcmain(){
varb1strings.Builder
b2:=b1
fmt.Println(b1.String())//輸出空行
fmt.Println(b2.String())//輸出空行
b2.WriteString("DEF")
fmt.Println(b1.String())//輸出空行
fmt.Println(b2.String())//輸出:DEF
b1.WriteString("ABC")
fmt.Println(b1.String())//輸出:ABC
fmt.Println(b2.String())//輸出:DEF
strings.Builder會在以下方法中檢測拷貝操作:
Grow(nint)
Write(p[]byte)
WriteRune(rrune)
WriteString(sstring)
所以,拷貝并使用下列這些方法是允許的:
funcmain(){
//Reset()
//Len()
//String()
varb1strings.Builder
b1.WriteString("ABC")
b2:=b1
fmt.Println(b2.Len())//3
fmt.Println(b2.String())//ABC
b2.Reset()
b2.WriteString("DEF")
fmt.Println(b2.String())//DEF
5.不能與nil作比較
6.Grow深入
strings.Builder是通過其內(nèi)部的slice來儲存內(nèi)容的。當(dāng)你調(diào)用寫入方法的時(shí)候,新的字節(jié)數(shù)據(jù)就被追加到slice上。如果達(dá)到了slice的容量(capacity)限制,一個(gè)新的slice就會被分配,然后老的slice上的內(nèi)容會被拷貝到新的slice上。當(dāng)slice長度很大時(shí),這個(gè)操作就會很消耗資源甚至引起內(nèi)存問題。我們需要避免這一情況。
關(guān)于slice,Go語言提供了make([]TypeOfSlice,length,capacity)方法在初始化的時(shí)候預(yù)定義它的容量。這就避免了因達(dá)到最大容量而引起擴(kuò)容。
strings.Builder同樣也提供了Grow()來支持預(yù)定義容量。當(dāng)我們可以預(yù)定義我們需要使用的容量時(shí),strings.Builder就能避免擴(kuò)容而創(chuàng)建新的slice了。
當(dāng)調(diào)用Grow()時(shí),我們必須定義要擴(kuò)容的字節(jié)數(shù)(n)。Grow()方法保證了其內(nèi)部的slice一定能夠?qū)懭雗個(gè)字節(jié)。只有當(dāng)slice空余空間不足以寫入n個(gè)字節(jié)時(shí),擴(kuò)容才有可能發(fā)生。
舉個(gè)例子:
builder內(nèi)部slice容量為10。
builder內(nèi)部slice長度為5。
當(dāng)我們調(diào)用Grow(3)=擴(kuò)容操作并不會發(fā)生。因?yàn)楫?dāng)前的空余空間為5,足以提供3個(gè)字節(jié)的寫入。
當(dāng)我們調(diào)用Grow(7)=擴(kuò)容操作發(fā)生。因?yàn)楫?dāng)前的空余空間為5,已不足以提供7個(gè)字節(jié)的寫入。
關(guān)于上面的情形,如果這時(shí)我們調(diào)用Grow(7),則擴(kuò)容之后的實(shí)際容量是多少?
17還是12
實(shí)際上,是27。strings.Builder的Grow()方法是通過current_capacity*2+n(n就是你想要擴(kuò)充的容量)的方式來對內(nèi)部的slice進(jìn)行擴(kuò)容的。所以說最后的容量是10*2+7=27。當(dāng)你預(yù)定義strings.Builder容量的時(shí)候還要注意一點(diǎn)。調(diào)用WriteRune()和WriteString()時(shí),rune和string的字符可能不止1個(gè)字節(jié)。因?yàn)?,你懂的,UTF-8的原因。
funcmain(){
varb1strings.Builder
fmt.Println(b1.Len())//0
fmt.Println(b1.Cap())//0
b1.Grow(3)
fmt.Println(b1.Len())//0
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年環(huán)境評估(土壤環(huán)境質(zhì)量評估)試題及答案
- 2025年中職(醫(yī)學(xué)檢驗(yàn))血常規(guī)檢測實(shí)務(wù)綜合測試題及答案
- 2025年大學(xué)(測繪科學(xué)與技術(shù)專業(yè))地理信息系統(tǒng)基礎(chǔ)試題及答案
- 2025年大學(xué)第四學(xué)年(工程項(xiàng)目融資)融資方案設(shè)計(jì)階段測試題及答案
- 2025年大學(xué)美術(shù)學(xué)(美術(shù)學(xué)概論)試題及答案
- 2025年大學(xué)安全教育(交通安全知識)試題及答案
- 2025年中職(市場開發(fā)實(shí)務(wù))客戶開發(fā)流程階段測試試題及答案
- 2025年中職船舶工程技術(shù)(船舶建造工藝)試題及答案
- 2025年中職道路橋梁工程技術(shù)(路橋施工技術(shù))試題及答案
- 2025年大學(xué)臨床醫(yī)學(xué)(臨床診療技術(shù))試題及答案
- 海南2025年中國熱帶農(nóng)業(yè)科學(xué)院橡膠研究所第一批招聘16人(第1號)筆試歷年參考題庫附帶答案詳解
- 2025-2026人教版數(shù)學(xué)七年級上冊期末模擬試卷(含答案)
- 廣告行業(yè)法律法規(guī)與行業(yè)規(guī)范(標(biāo)準(zhǔn)版)
- 2026年國安民警副科級面試題及實(shí)戰(zhàn)解答
- 2026年紀(jì)檢監(jiān)察室工作面試題集
- 浙江省紹興市諸暨市2024-2025學(xué)年四年級上冊期末考試數(shù)學(xué)試卷(含答案)
- 廣東省廣州市天河區(qū)2024-2025學(xué)年七年級上學(xué)期期末考試語文試題(含答案)
- 11340《古代小說戲曲專題》國家開放大學(xué)期末考試題庫
- 江蘇省淮安市淮陰區(qū)事業(yè)單位考試試題2025年附答案
- ups拆除施工方案
- GB/T 21196.4-2007紡織品馬丁代爾法織物耐磨性的測定第4部分:外觀變化的評定
評論
0/150
提交評論