操作字符串離不開字符串的拼接,但是Go中string是只讀類型,大量字符串的拼接會(huì)造成性能問題。
創(chuàng)新互聯(lián)公司2013年至今,先為平和等服務(wù)建站,平和等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為平和企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
拼接字符串,無外乎四種方式,采用“+”,“fmt.Sprintf()”,"bytes.Buffer","strings.Builder"
上面我們創(chuàng)建10萬字符串拼接的測(cè)試,可以發(fā)現(xiàn)"bytes.Buffer","strings.Builder"的性能最好,約是“+”的1000倍級(jí)別。
這是由于string是不可修改的,所以在使用“+”進(jìn)行拼接字符串,每次都會(huì)產(chǎn)生申請(qǐng)空間,拼接,復(fù)制等操作,數(shù)據(jù)量大的情況下非常消耗資源和性能。而采用Buffer等方式,都是預(yù)先計(jì)算拼接字符串?dāng)?shù)組的總長度(如果可以知道長度),申請(qǐng)空間,底層是slice數(shù)組,可以以append的形式向后進(jìn)行追加。最后在轉(zhuǎn)換為字符串。這申請(qǐng)了不斷申請(qǐng)空間的操作,也減少了空間的使用和拷貝的次數(shù),自然性能也高不少。
bytes.buffer是一個(gè)緩沖byte類型的緩沖器存放著都是byte
是一個(gè)變長的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一個(gè) 空的 buffer,但是可以使用,底層就是一個(gè) []byte, 字節(jié)切片。
向Buffer中寫數(shù)據(jù),可以看出Buffer中有個(gè)Grow函數(shù)用于對(duì)切片進(jìn)行擴(kuò)容。
從Buffer中讀取數(shù)據(jù)
strings.Builder的方法和bytes.Buffer的方法的命名幾乎一致。
但實(shí)現(xiàn)并不一致,Builder的Write方法直接將字符拼接slice數(shù)組后。
其沒有提供read方法,但提供了strings.Reader方式
Reader 結(jié)構(gòu):
Buffer:
Builder:
可以看出Buffer和Builder底層都是采用[]byte數(shù)組進(jìn)行裝載數(shù)據(jù)。
先來說說Buffer:
創(chuàng)建好Buffer是一個(gè)empty的,off 用于指向讀寫的尾部。
在寫的時(shí)候,先判斷當(dāng)前寫入字符串長度是否大于Buffer的容量,如果大于就調(diào)用grow進(jìn)行擴(kuò)容,擴(kuò)容申請(qǐng)的長度為當(dāng)前寫入字符串的長度。如果當(dāng)前寫入字符串長度小于最小字節(jié)長度64,直接創(chuàng)建64長度的[]byte數(shù)組。如果申請(qǐng)的長度小于二分之一總?cè)萘繙p去當(dāng)前字符總長度,說明存在很大一部分被使用但已讀,可以將未讀的數(shù)據(jù)滑動(dòng)到數(shù)組頭。如果容量不足,擴(kuò)展2*c + n 。
其String()方法就是將字節(jié)數(shù)組強(qiáng)轉(zhuǎn)為string
Builder是如何實(shí)現(xiàn)的。
Builder采用append的方式向字節(jié)數(shù)組后添加字符串。
從上面可以看出,[]byte的內(nèi)存大小也是以倍數(shù)進(jìn)行申請(qǐng)的,初始大小為 0,第一次為大于當(dāng)前申請(qǐng)的最大 2 的指數(shù),不夠進(jìn)行翻倍.
可以看出如果舊容量小于1024進(jìn)行翻倍,否則擴(kuò)展四分之一。(2048 byte 后,申請(qǐng)策略的調(diào)整)。
其次String()方法與Buffer的string方法也有明顯區(qū)別。Buffer的string是一種強(qiáng)轉(zhuǎn),我們知道在強(qiáng)轉(zhuǎn)的時(shí)候是需要進(jìn)行申請(qǐng)空間,并拷貝的。而Builder只是指針的轉(zhuǎn)換。
這里我們解析一下 *(*string)(unsafe.Pointer(b.buf)) 這個(gè)語句的意思。
先來了解下unsafe.Pointer 的用法。
也就是說,unsafe.Pointer 可以轉(zhuǎn)換為任意類型,那么意味著,通過unsafe.Pointer媒介,程序繞過類型系統(tǒng),進(jìn)行地址轉(zhuǎn)換而不是拷貝。
即*A = Pointer = *B
就像上面例子一樣,將字節(jié)數(shù)組轉(zhuǎn)為unsafe.Pointer類型,再轉(zhuǎn)為string類型,s和b中內(nèi)容一樣,修改b,s也變了,說明b和s是同一個(gè)地址。但是對(duì)s重新賦值后,意味著s的地址指向了“WORLD”,它們所使用的內(nèi)存空間不同了,所以s改變后,b并不會(huì)改變。
所以他們的區(qū)別就在于 bytes.Buffer 是重新申請(qǐng)了一塊空間,存放生成的string變量, 而strings.Builder直接將底層的[]byte轉(zhuǎn)換成了string類型返回了回來,去掉了申請(qǐng)空間的操作。
通過String.valueOf(char)函數(shù)把字符轉(zhuǎn)化成字符串舉例char a='A';//定義一個(gè)字符aString str = String.valueOf(a);//把字符a轉(zhuǎn)換成字符串str
Go語言的string模塊包含了ToLower和ToUpper函數(shù),用于將字符串轉(zhuǎn)換成小寫和大寫
代碼如下:
package main
import (
"fmt"
"strings"
)
func main() {
fmt.Println(strings.ToUpper("hello world"))
}
import "strconv"
int, err := strconv.Atoi(string)
int64, err := strconv.ParseInt(string, 10, 64)
string := strconv.Itoa(int)
string := strconv.FormatInt(int64,15)
fmt.Sprint()的參數(shù)為interface,可以將任意的類型轉(zhuǎn)為string
函數(shù)原型:func FormatInt(i int64, base int) string
參數(shù)說明:base為進(jìn)制數(shù)
base為十和十六進(jìn)制數(shù)的區(qū)別的舉例
先介紹幾種常用的方法:
1、使用MatchString函數(shù)或Match函數(shù)
regexp.MatchString(pattern string, s string) pattern為正則表達(dá)式,s為需要校驗(yàn)的字符串
regexp.Match(pattern string, b []byte) pattern為正則表達(dá)式,s為需要校驗(yàn)的字符串
它們的作用都是匹配,區(qū)別在于參數(shù)為字符串和切片
實(shí)例如下:
2、使用 Compile函數(shù)或MustCompile函數(shù)
它們的區(qū)別是Compile返回兩個(gè)參數(shù) Regexp,error類型,而MustCompile只返回 Regexp類型
它們的作用是將正則表達(dá)式進(jìn)行編譯,返回優(yōu)化的 Regexp 結(jié)構(gòu)體,該結(jié)構(gòu)體有需多方法。
實(shí)例如下:
3、查找正則匹配字串( 注:函數(shù)名包含string的所傳參數(shù)為string 其他的均為[]byte 帶All是所有)
查找正則匹配的字符串位置( 注:函數(shù)名包含string的所傳參數(shù)為string 其他的均為[]byte 帶All是所有)
4、替換
正則替換
按原文替換
函數(shù)處理替換源字串
5、Regexp結(jié)構(gòu)體中一些常用的方法