国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

go基礎(chǔ)10 -字符串的高效構(gòu)造與轉(zhuǎn)換

這篇具有很好參考價值的文章主要介紹了go基礎(chǔ)10 -字符串的高效構(gòu)造與轉(zhuǎn)換。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前面提到過,Go原生支持通過+/+=操作符來連接多個字符串以構(gòu)造一個更長的字符串,并且通過+/+=操作符的字符串連接構(gòu)造是最自然、開發(fā)體驗最好的一種。

但Go還提供了其他一些構(gòu)造字符串的方法,比如:
● 使用fmt.Sprintf;
● 使用strings.Join;
● 使用strings.Builder;
● 使用bytes.Buffer。
在這些方法中哪種方法最為高效呢?我們使用基準(zhǔn)測試的數(shù)據(jù)作為參考:

var sl []string = []string{
"Rob Pike ",
"Robert Griesemer ",
"Ken Thompson ",
}
func concatStringByOperator(sl []string) string {
var s string
for _, v := range sl {
s += v
}
return s
}
func concatStringBySprintf(sl []string) string {
var s string
for _, v := range sl {
s = fmt.Sprintf("%s%s", s, v)
}
return s
}
func concatStringByJoin(sl []string) string {
return strings.Join(sl, "")
}
func concatStringByStringsBuilder(sl []string) string {
var b strings.Builder
for _, v := range sl {
b.WriteString(v)
}
return b.String()
}
func concatStringByStringsBuilderWithInitSize(sl []string) string {
var b strings.Builder
b.Grow(64)
 for _, v := range sl {
b.WriteString(v)
}
return b.String()
}
func concatStringByBytesBuffer(sl []string) string {
var b bytes.Buffer
for _, v := range sl {
b.WriteString(v)
}
return b.String()
}
func concatStringByBytesBufferWithInitSize(sl []string) string {
buf := make([]byte, 0, 64)
b := bytes.NewBuffer(buf)
for _, v := range sl {
b.WriteString(v)
}
return b.String()
}
func BenchmarkConcatStringByOperator(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByOperator(sl)
}
}
func BenchmarkConcatStringBySprintf(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringBySprintf(sl)
}
}
func BenchmarkConcatStringByJoin(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByJoin(sl)
}
}
func BenchmarkConcatStringByStringsBuilder(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByStringsBuilder(sl)
}
}
func BenchmarkConcatStringByStringsBuilderWithInitSize(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByStringsBuilderWithInitSize(sl)
}
}
func BenchmarkConcatStringByBytesBuffer(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByBytesBuffer(sl)
}
}
func BenchmarkConcatStringByBytesBufferWithInitSize(b *testing.B) {
for n := 0; n < b.N; n++ {
concatStringByBytesBufferWithInitSize(sl)
}
}

運行該基準(zhǔn)測試:

$go test -bench=. -benchmem ./string_concat_benchmark_test.go
goos: darwin
goarch: amd64
BenchmarkConcatStringByOperator-8 11744653 89.1 ns/op 80 B/op 2 allocs/op
BenchmarkConcatStringBySprintf-8 2792876 420 ns/op 176 B/op 8 allocs/op
BenchmarkConcatStringByJoin-8 22923051 49.1 ns/op 48 B/op 1 allocs/op
BenchmarkConcatStringByStringsBuilder-8 11347185 96.6 ns/op 112 B/op 3 allocs/op
BenchmarkConcatStringByStringsBuilderWithInitSize-8 26315769 42.3 ns/op 64 B/op 1 allocs/op
BenchmarkConcatStringByBytesBuffer-8 14265033 82.6 ns/op 112 B/op 2 allocs/op
BenchmarkConcatStringByBytesBufferWithInitSize-8 24777525 48.1 ns/op 48 B/op 1 allocs/op
PASS
ok command-line-arguments 8.816s

從基準(zhǔn)測試的輸出結(jié)果的第三列,即每操作耗時的數(shù)值來看:

● 做了預(yù)初始化的strings.Builder連接構(gòu)建字符串效率最高;

● 帶有預(yù)初始化的bytes.Buffer和strings.Join這兩種方法效率十分接近,分列二三位;

● 未做預(yù)初始化的strings.Builder、bytes.Buffer和操作符連接在第三檔次;

● fmt.Sprintf性能最差,排在末尾。

由此可以得出一些結(jié)論:

● 在能預(yù)估出最終字符串長度的情況下,使用預(yù)初始化的strings.Builder連接構(gòu)建字符串效率最高;

● strings.Join連接構(gòu)建字符串的平均性能最穩(wěn)定,如果輸入的多個字符串是以[]string承載的,那么strings.Join也是不錯的選擇;

● 使用操作符連接的方式最直觀、最自然,在編譯器知曉欲連接的字符串個數(shù)的情況下,使用此種方式可以得到編譯器的優(yōu)化處理;

● fmt.Sprintf雖然效率不高,但也不是一無是處,如果是由多種不同類型變量來構(gòu)建特定格式的字符串,那么這種方式還是最適合的。

轉(zhuǎn)換

在前面的例子中,我們看到了string到[]rune以及string到[]byte的轉(zhuǎn)換,這兩個轉(zhuǎn)
換也是可逆的,也就是說string和[]rune、[]byte可以雙向轉(zhuǎn)換。下面就是從[]rune或
[]byte反向轉(zhuǎn)換為string的例子:

func main() {
	rs := []rune{
		0x4E2D,
		0x56FD,
		0x6B22,
		0x8FCE,
		0x60A8,
	}
	s := string(rs)
	fmt.Println(s)
	sl := []byte{
	0xE4, 0xB8, 0xAD,
	0xE5, 0x9B, 0xBD,
	0xE6, 0xAC, 0xA2,
	0xE8, 0xBF, 0x8E,
	0xE6, 0x82, 0xA8,
	}
	s = string(sl)
	fmt.Println(s)
}
$go run string_slice_to_string.go
中國歡迎您
中國歡迎您

無論是string轉(zhuǎn)slice還是slice轉(zhuǎn)string,轉(zhuǎn)換都是要付出代價的,這些代價的根源
在于string是不可變的,運行時要為轉(zhuǎn)換后的類型分配新內(nèi)存。我們以byte slice與
string相互轉(zhuǎn)換為例,看看轉(zhuǎn)換過程的內(nèi)存分配情況:

func byteSliceToString() {
sl := []byte{
0xE4, 0xB8, 0xAD,
0xE5, 0x9B, 0xBD,
0xE6, 0xAC, 0xA2,
0xE8, 0xBF, 0x8E,
0xE6, 0x82, 0xA8,
0xEF, 0xBC, 0x8C,
0xE5, 0x8C, 0x97,
0xE4, 0xBA, 0xAC,
0xE6, 0xAC, 0xA2,
0xE8, 0xBF, 0x8E,
 0xE6, 0x82, 0xA8,
}
_ = string(sl)
}
func stringToByteSlice() {
s := "中國歡迎您,北京歡迎您"
_ = []byte(s)
}
func main() {
fmt.Println(testing.AllocsPerRun(1, byteSliceToString))
fmt.Println(testing.AllocsPerRun(1, stringToByteSlice))
}

運行這個例子:

$go run string_mallocs_in_convert.go
1
1

我們看到,針對“中國歡迎您,北京歡迎您”這個長度的字符串,在string與byte
slice互轉(zhuǎn)的過程中都要有一次內(nèi)存分配操作。

在Go運行時層面,字符串與rune slice、byte slice相互轉(zhuǎn)換對應(yīng)的函數(shù)如下:

slicebytetostring: []byte -> string
slicerunetostring: []rune -> string
stringtoslicebyte: string -> []byte
stringtoslicerune: string -> []rune

以byte slice為例,看看slicebytetostring和stringtoslicebyte的實現(xiàn):

const tmpStringBufSize = 32
type tmpBuf [tmpStringBufSize]byte
func stringtoslicebyte(buf *tmpBuf, s string) []byte {
var b []byte
if buf != nil && len(s) <= len(buf) {
*buf = tmpBuf{}
b = buf[:len(s)]
} else {
b = rawbyteslice(len(s))
}
copy(b, s)
return b
}


func slicebytetostring(buf *tmpBuf, b []byte) (str string) {
	l := len(b)
	 if l == 0 {
		return ""
	}
	// 此處省略一些代碼
	if l == 1 {
	stringStructOf(&str).str = unsafe.Pointer(&staticbytes[b[0]])
	stringStructOf(&str).len = 1
	return
	}
	var p unsafe.Pointer
	if buf != nil && len(b) <= len(buf) {
	p = unsafe.Pointer(buf)
	} else {
	p = mallocgc(uintptr(len(b)), nil, false)
	}
	stringStructOf(&str).str = p
	stringStructOf(&str).len = len(b)
	memmove(p, (*(*slice)(unsafe.Pointer(&b))).array, uintptr(len(b)))
	return
}

想要更高效地進(jìn)行轉(zhuǎn)換,唯一的方法就是減少甚至避免額外的內(nèi)存分配操作。我們看
到運行時實現(xiàn)轉(zhuǎn)換的函數(shù)中已經(jīng)加入了一些避免每種情況都要分配新內(nèi)存操作的優(yōu)化(如
tmpBuf的復(fù)用)。
slice類型是不可比較的,而string類型是可比較的,因此在日常Go編碼中,我們會經(jīng)
常遇到將slice臨時轉(zhuǎn)換為string的情況。Go編譯器為這樣的場景提供了優(yōu)化。在運行時中
有一個名為slicebytetostringtmp的函數(shù)就是協(xié)助實現(xiàn)這一優(yōu)化的:

func slicebytetostringtmp(b []byte) string {
	if raceenabled && len(b) > 0 {
		racereadrangepc(unsafe.Pointer(&b[0]),
		uintptr(len(b)),
		getcallerpc(),
	funcPC(slicebytetostringtmp))
	}
	if msanenabled && len(b) > 0 {
		msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
	}
	return *(*string)(unsafe.Pointer(&b))
}

該函數(shù)的“秘訣”就在于不為string新開辟一塊內(nèi)存,而是直接使用slice的底層存
儲。當(dāng)然使用這個函數(shù)的前提是:在原slice被修改后,這個string不能再被使用了。因此
這樣的優(yōu)化是針對以下幾個特定場景的。

1)string(b)用在map類型的key中

b := []byte{'k', 'e', 'y'}
m := make(map[string]string)
m[string(b)] = "value"
m[[3]string{string(b), "key1", "key2"}] = "value1"2string(b)用在字符串連接語句中
b := []byte{'t', 'o', 'n', 'y'}
s := "hello " + string(b) + "!"3string(b)用在字符串比較中
s := "tom"
b := []byte{'t', 'o', 'n', 'y'}
if s < string(b) {
...
}

Go編譯器對用在for-range循環(huán)中的string到[]byte的轉(zhuǎn)換也有優(yōu)化處理,它不會為
[]byte進(jìn)行額外的內(nèi)存分配,而是直接使用string的底層數(shù)據(jù)。

看下面的例子:

func convert() {
s := "中國歡迎您,北京歡迎您"
sl := []byte(s)
for _, v := range sl {
_ = v
}
}
func convertWithOptimize() {
s := "中國歡迎您,北京歡迎您"
for _, v := range []byte(s) {
_ = v
}
}
func main() {
fmt.Println(testing.AllocsPerRun(1, convert))
fmt.Println(testing.AllocsPerRun(1, convertWithOptimize))
}

運行這個例子程序:

$go run string_for_range_covert_optimize.go
1
0

從結(jié)果我們看到,convertWithOptimize函數(shù)將string到[]byte的轉(zhuǎn)換放在for-range
循環(huán)中,Go編譯器對其進(jìn)行了優(yōu)化,節(jié)省了一次內(nèi)存分配操作。
文章來源地址http://www.zghlxwxcb.cn/news/detail-703952.html

到了這里,關(guān)于go基礎(chǔ)10 -字符串的高效構(gòu)造與轉(zhuǎn)換的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • go基礎(chǔ)09-Go語言的字符串類型

    字符串類型是現(xiàn)代編程語言中最常使用的數(shù)據(jù)類型之一。在Go語言的先祖之一C語言當(dāng)中,字符串類型并沒有被顯式定義,而是以字符串字面值常量或以’\\0’結(jié)尾的字符類型(char)數(shù)組來呈現(xiàn)的: 這給C程序員在使用字符串時帶來一些問題,諸如: ● 類型安全性差; ● 字符

    2024年02月09日
    瀏覽(28)
  • 【Go基礎(chǔ)】編譯、變量、常量、基本數(shù)據(jù)類型、字符串

    【Go基礎(chǔ)】編譯、變量、常量、基本數(shù)據(jù)類型、字符串

    面試題文檔下鏈接點擊這里免積分下載 go語言入門到精通點擊這里免積分下載 使用 go build 1.在項目目錄下執(zhí)行 2.在其他路徑下編譯 go build ,需要再后面加上項目的路徑(項目路徑從GOPATH/src后開始寫起,編譯之后的可執(zhí)行文件就保存再當(dāng)前目錄) 3.打包的時候自定義名字:

    2024年02月09日
    瀏覽(28)
  • 【Java 基礎(chǔ)篇】Java StringBuffer詳解:更高效的字符串處理

    【Java 基礎(chǔ)篇】Java StringBuffer詳解:更高效的字符串處理

    在Java編程中,字符串是一個常見的數(shù)據(jù)類型,用于存儲文本信息。然而,與字符串相關(guān)的操作可能會導(dǎo)致性能問題,因為字符串是不可變的,每次對字符串進(jìn)行操作都會創(chuàng)建一個新的字符串對象。為了解決這個問題,Java提供了 StringBuffer 類,它允許我們有效地處理可變字符串

    2024年02月10日
    瀏覽(15)
  • MFC 編輯框輸入16進(jìn)制字符串轉(zhuǎn)換為16進(jìn)制數(shù)或者10進(jìn)制數(shù)據(jù)計算

    1. 編輯框添加變量,并選擇變量類型為CString。 ?? ?CString m_strReg; ?? ?? ?DDX_Text(pDX, IDC_EDIT_REG, m_strReg); 2. 使用“strtoul”或“_tcstoul”函數(shù)將Cstring 類型轉(zhuǎn)換為16進(jìn)制/10進(jìn)制數(shù)進(jìn)行計算。 ?? ?CString tmp; ?? ?UpdateData(TRUE); ?? ?UpdateData(FALSE); ?? ? ?? ?OutputDebugString(m_strReg); ?

    2024年02月16日
    瀏覽(31)
  • 【C語言基礎(chǔ)考研向】10 字符數(shù)組初始化及傳遞和scanf 讀取字符串

    字符數(shù)組的定義方法與前面介紹的一維數(shù)組類似.例如, 字符數(shù)組的初始化可以采用以下方式. (1)對每個字符單獨賦值進(jìn)行初始化.例如, (2)對整個數(shù)組進(jìn)行初始化.例如, 但工作中一般不用以上兩種初始化方式,因為字符數(shù)組一般用來存取字符串.通常采用的初始化方式是

    2024年01月25日
    瀏覽(30)
  • 力扣2182.構(gòu)造限制重復(fù)的字符串

    力扣2182.構(gòu)造限制重復(fù)的字符串

    ?思路:先記錄每個字符的出現(xiàn)次數(shù),構(gòu)建一個新字符串,從尾取字符,每取一個該字符個數(shù)-1,若該字符已經(jīng)取到有repeatLimit個,則遞歸取次大的字符,并對應(yīng)字符個數(shù)-1,若沒有次大字符了,則直接返回 代碼: ?

    2024年02月01日
    瀏覽(22)
  • 2645. 構(gòu)造有效字符串的最少插入數(shù)

    給你一個字符串? word ?,你可以向其中任何位置插入 \\\"a\\\"、\\\"b\\\" 或 \\\"c\\\" 任意次,返回使? word ? 有效 ?需要插入的最少字母數(shù)。 如果字符串可以由 \\\"abc\\\" 串聯(lián)多次得到,則認(rèn)為該字符串? 有效 ?。 示例 1: 示例 2: 示例 3: 提示: 1 = word.length = 50 word ?僅由字母 \\\"a\\\"、\\\"b\\\" 和 \\\"c\\\" 組成

    2024年01月20日
    瀏覽(19)
  • 【每日一題】構(gòu)造限制重復(fù)的字符串

    【每日一題】構(gòu)造限制重復(fù)的字符串

    【貪心】【字符串】【2024-01-13】 2182. 構(gòu)造限制重復(fù)的字符串 思路 解題思想比較簡單,利用貪心思想,每次選擇當(dāng)前剩余字符串中字典序最大的字符加到答案字符串末尾,如果答案字符串末尾的字符已經(jīng)連續(xù)出現(xiàn)了 repeatLimit 次,則將字典序次大的字符加到答案字符串,隨后

    2024年01月22日
    瀏覽(30)
  • 【Kotlin】基礎(chǔ)速覽(1):操作符 | 內(nèi)建類型 | 類型轉(zhuǎn)換 | 字符串模板 | 可變 var 和不可變 val

    【Kotlin】基礎(chǔ)速覽(1):操作符 | 內(nèi)建類型 | 類型轉(zhuǎn)換 | 字符串模板 | 可變 var 和不可變 val

    ? ?? 本章目錄: 0x00 操作符(operators) 0x01 內(nèi)建類型(Build-in) 0x02 類型轉(zhuǎn)換:顯式類型轉(zhuǎn)換 0x03 在較長數(shù)字中使用下劃線 0x04 字符串(String) 0x05 字符串模板(String Templates) 0x06 字符串連接(變量插值) 0x06?指定變量類型 0x07 可變 var?和不可變 val 0x00 操作符(operators)

    2024年02月11日
    瀏覽(26)
  • 【算法題】2745. 構(gòu)造最長的新字符串

    給你三個整數(shù) x ,y 和 z 。 這三個整數(shù)表示你有 x 個 “AA” 字符串,y 個 “BB” 字符串,和 z 個 “AB” 字符串。你需要選擇這些字符串中的部分字符串(可以全部選擇也可以一個都不選擇),將它們按順序連接得到一個新的字符串。新字符串不能包含子字符串 “AAA” 或者

    2024年02月12日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包