操作字符串離不開(kāi)字符串的拼接,但是Go中string是只讀類(lèi)型,大量字符串的拼接會(huì)造成性能問(wèn)題。
瓊結(jié)ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書(shū)合作)期待與您的合作!
拼接字符串,無(wú)外乎四種方式,采用“+”,“fmt.Sprintf()”,"bytes.Buffer","strings.Builder"
上面我們創(chuàng)建10萬(wàn)字符串拼接的測(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ù)組的總長(zhǎng)度(如果可以知道長(zhǎng)度),申請(qǐng)空間,底層是slice數(shù)組,可以以append的形式向后進(jìn)行追加。最后在轉(zhuǎn)換為字符串。這申請(qǐng)了不斷申請(qǐng)空間的操作,也減少了空間的使用和拷貝的次數(shù),自然性能也高不少。
bytes.buffer是一個(gè)緩沖byte類(lèi)型的緩沖器存放著都是byte
是一個(gè)變長(zhǎng)的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一個(gè) 空的 buffer,但是可以使用,底層就是一個(gè) []byte, 字節(jié)切片。
向Buffer中寫(xiě)數(shù)據(jù),可以看出Buffer中有個(gè)Grow函數(shù)用于對(duì)切片進(jìn)行擴(kuò)容。
從Buffer中讀取數(shù)據(jù)
strings.Builder的方法和bytes.Buffer的方法的命名幾乎一致。
但實(shí)現(xiàn)并不一致,Builder的Write方法直接將字符拼接slice數(shù)組后。
其沒(méi)有提供read方法,但提供了strings.Reader方式
Reader 結(jié)構(gòu):
Buffer:
Builder:
可以看出Buffer和Builder底層都是采用[]byte數(shù)組進(jìn)行裝載數(shù)據(jù)。
先來(lái)說(shuō)說(shuō)Buffer:
創(chuàng)建好Buffer是一個(gè)empty的,off 用于指向讀寫(xiě)的尾部。
在寫(xiě)的時(shí)候,先判斷當(dāng)前寫(xiě)入字符串長(zhǎng)度是否大于Buffer的容量,如果大于就調(diào)用grow進(jìn)行擴(kuò)容,擴(kuò)容申請(qǐng)的長(zhǎng)度為當(dāng)前寫(xiě)入字符串的長(zhǎng)度。如果當(dāng)前寫(xiě)入字符串長(zhǎng)度小于最小字節(jié)長(zhǎng)度64,直接創(chuàng)建64長(zhǎng)度的[]byte數(shù)組。如果申請(qǐng)的長(zhǎng)度小于二分之一總?cè)萘繙p去當(dāng)前字符總長(zhǎng)度,說(shuō)明存在很大一部分被使用但已讀,可以將未讀的數(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)空間,并拷貝的。而B(niǎo)uilder只是指針的轉(zhuǎn)換。
這里我們解析一下 *(*string)(unsafe.Pointer(b.buf)) 這個(gè)語(yǔ)句的意思。
先來(lái)了解下unsafe.Pointer 的用法。
也就是說(shuō),unsafe.Pointer 可以轉(zhuǎn)換為任意類(lèi)型,那么意味著,通過(guò)unsafe.Pointer媒介,程序繞過(guò)類(lèi)型系統(tǒng),進(jìn)行地址轉(zhuǎn)換而不是拷貝。
即*A = Pointer = *B
就像上面例子一樣,將字節(jié)數(shù)組轉(zhuǎn)為unsafe.Pointer類(lèi)型,再轉(zhuǎn)為string類(lèi)型,s和b中內(nèi)容一樣,修改b,s也變了,說(shuō)明b和s是同一個(gè)地址。但是對(duì)s重新賦值后,意味著s的地址指向了“WORLD”,它們所使用的內(nèi)存空間不同了,所以s改變后,b并不會(huì)改變。
所以他們的區(qū)別就在于 bytes.Buffer 是重新申請(qǐng)了一塊空間,存放生成的string變量, 而strings.Builder直接將底層的[]byte轉(zhuǎn)換成了string類(lèi)型返回了回來(lái),去掉了申請(qǐng)空間的操作。
你是說(shuō) goto 標(biāo)號(hào)? 把標(biāo)號(hào)換成變量?
不好這么做,標(biāo)號(hào)到是可以換成自定義的常量,變量不行
你要非用變量
直接寫(xiě)判斷if,然后執(zhí)行不同的goto不就好了么
話說(shuō) goto 還是少用點(diǎn),多了會(huì)亂
Go語(yǔ)言模板文件可以引入js文件或css文件,但是在引入的過(guò)程中,需要注意以下幾點(diǎn):
1. 引入的文件路徑應(yīng)該是相對(duì)路徑,而不是絕對(duì)路徑。
2. 在引入js文件時(shí),需要使用{{ url }} 模板函數(shù),用來(lái)拼接路徑, 這樣可以更好的兼容不同的路徑。
3. 如果是在統(tǒng)一的文件夾中的js文件,最好使用{{ static }}模板函數(shù),這樣可以更好的節(jié)省路徑長(zhǎng)度。
4. 在引用js文件時(shí),需要在頁(yè)面底部,可以使用{{ template }}模板函數(shù),這樣可以保證js文件在頁(yè)面加載完成之前就被加載。
總之,使用Go語(yǔ)言模板文件引入js文件,需要注意路徑的相對(duì)性,并且使用模板函數(shù)來(lái)拼接路徑,這樣可以更好的兼容不同的路徑,從而保證引用js文件的正確性。