Golang 中的字符串:常見錯(cuò)誤和最佳實(shí)踐

1024

在這個(gè)對(duì)程序員有意義的節(jié)日里,希望大家快樂柒啤,少加班,開開心心寫代碼畸颅。

正題

在這篇文章中,我們將討論 Golang 中的字符串方援,并查看一些不同的場(chǎng)景没炒,以避免常見錯(cuò)誤。讓我們深入探討犯戏!

1. 字符串是否可以為 nil送火?

我們已經(jīng)對(duì) Golang 中的字符串有了基本的了解,但我們可以從 Golang 字符串不能為 nil 開始先匪,除非您使用指向字符串的指針。

如下代碼所示,當(dāng)我們創(chuàng)建一個(gè)字符串變量時(shí)馒过,默認(rèn)值必須是空的""禽作。如果我們用 nil 值初始化字符串變量,我們將面臨在變量聲明中不能使用 nil 作為字符串值的錯(cuò)誤岸裙。例如:

func main() {
    var s string
    s = nil // Cannot use 'nil' as the type string
    fmt.Println(s)
}

編譯器會(huì)提示我們不能使用 nil 賦予 string 類型猖败。因此,我們可以只是定義變量降允,或者使用""作為默認(rèn)值:

func main() {
    var s string
    var ss = ""
    fmt.Println(s, ss)
}

如果我們堅(jiān)持在字符串類型變量中使用 nil 值恩闻,則應(yīng)使用指針,如下所示:

func main() {
    var s *string
    fmt.Println(s)
}

這個(gè)時(shí)候輸出則為:

<nil>

但是剧董,我們必須謹(jǐn)慎使用這種方法幢尚。每次要為變量賦值時(shí)破停,我們都必須編寫更多的代碼,而且在賦新值之前還要檢查是否有零值或前一個(gè)值尉剩。

func main() {
    var s *string
    tmp := "hello"
    s = &tmp
    fmt.Printf("address: %+v, value: %s", s, *s)
}

這個(gè)時(shí)候打印出來(lái) s 的地址以及所指向的值:

address: 0xc00008a030, value: hello

2. 字符串是不可變的

Golang 中的字符串是不可變的辱挥,這意味著我們不能更改每個(gè)字符的值。例如:

func main() {
    tmp := "hello"
    tmp[0] = 'J'
    fmt.Println(tmp)
}

上述代碼會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤边涕,因?yàn)闊o(wú)法賦值給 tmp[0]晤碘。

更改字符串中單個(gè)字符的常見錯(cuò)誤如下:

func main() {
    tmp := "hello"
    tbs := []byte(tmp)
    tbs[0] = 'J'
    fmt.Println(string(tbs))

    chi := "你好"
    chiTBS := []byte(chi)
    chiTBS[0] = 'J'
    fmt.Println(string(chiTBS))
}

輸出為:

Jello
J??好

雖然第一個(gè)輸出顯示的結(jié)果符合我們的預(yù)期,但這并不是更改某個(gè)字符的正確方法功蜓。

這是因?yàn)槲覀兇蛩阈薷牡膯蝹€(gè)部分可能存儲(chǔ)在多個(gè)字節(jié)中园爷,即使你想將變量轉(zhuǎn)換為符文類型并更改你想要的部分,我也不得不說(shuō)式撼,這是不可能做到的童社,因?yàn)樗赡鼙环胖迷诙鄠€(gè)符文中,我們需要謹(jǐn)慎行事著隆!

3. 字符串是字節(jié)數(shù)組

在 Golang 中扰楼,字符串由字節(jié)(字節(jié)的片段)組成,某些字符需要存儲(chǔ)在多個(gè)字節(jié)中美浦,例如:"?"弦赖。

因此,當(dāng)需要確定一個(gè)字符串類型變量的長(zhǎng)度時(shí)浦辨,我們必須謹(jǐn)慎編碼蹬竖。例如

func main() {
    tmp := "¥"
    fmt.Println("bytes: ", len(tmp))
    fmt.Println("runes: ", utf8.RuneCountInString(tmp))
}

len 函數(shù)返回的是字符串的字節(jié)數(shù),而不是字符數(shù)流酬。當(dāng)我們需要找出字符串的符文數(shù)時(shí)币厕,可以使用 uft8.RuneCountIntString() 函數(shù)。

另一個(gè)常見的誤解是使用 uft8.RuneCountIntString() 來(lái)確定字符數(shù)芽腾,但這并不是在任何情況下都正確旦装,因?yàn)橐粋€(gè)字符串變量可能跨越多個(gè)符文。請(qǐng)看這個(gè)例子:

func main() {
    tmp := "??"
    fmt.Println("bytes: ", len(tmp))
    fmt.Println("runes: ", utf8.RuneCountInString(tmp))
}

輸出為:

bytes:  6
runes:  2

4. 字符串索引和forrange

在 Golang 中摊滔,使用索引檢索字符串的單個(gè)部分將為我們提供字符的 uint 值阴绢,并且只能檢索第一個(gè)字節(jié)。但在字符串變量的 for 循環(huán)中惭载,我們可以訪問每個(gè)字符的符值:

func main() {
    tmp := "?¥%……&*"
    fmt.Printf("char at 0 index, has type %T and value is %+v\n", tmp[0], tmp[0])

    for _, t := range tmp {
        fmt.Printf("value is %+v type is %T\n", t, t)
    }
}

輸出:

char at 0 index, has type uint8 and value is 226
value is 10084 type is int32
value is 65509 type is int32
value is 37 type is int32
value is 8230 type is int32
value is 8230 type is int32
value is 38 type is int32
value is 42 type is int32

在對(duì)字符串進(jìn)行迭代時(shí)旱函,還要注意變量中可能存在的非 UTF8 字符,如果 Golang 無(wú)法將其理解為 UTF8描滔,則會(huì)使用 unicode 替換而非實(shí)際值棒妨。

5. 字符串平等

在 Golang 中,我們總是可以使用 == 來(lái)檢查簡(jiǎn)單的字符串是否相等,但如果我們的變量存在隱藏點(diǎn)券腔,則應(yīng)在比較兩個(gè)字符串變量之前使用 unicode 規(guī)范包將其規(guī)范化:

func main() {
    cafe1 := "Café"
    cafe2 := "Cafe\u0301"

    normalizeCafe1 := norm.NFC.String(cafe1)
    normalizeCafe2 := norm.NFC.String(cafe2)
    fmt.Println(cafe1 == cafe2)
    fmt.Println(normalizeCafe1 == normalizeCafe2)
}

6. 高效字符串構(gòu)建

使用“+”連接大量字符串的效率可能非常低伏穆。使用 strings.Builder 是高效構(gòu)建字符串的最佳方法之一:

func main() {
    sb := strings.Builder{}
    for i := 0; i < 1000; i++ {
        sb.WriteString("hello ")
    }
    result := sb.String()
    fmt.Println(result)
}

與傳統(tǒng)的 + 連接方法相比,這種方法速度更快纷纫,內(nèi)存消耗更少枕扫,而且可以避免創(chuàng)建不必要的中間字符串。我們還可以使用 bytes.Buffer 軟件包來(lái)實(shí)現(xiàn)這一目標(biāo)辱魁。

總結(jié)

  • 字符串的默認(rèn)值是""
  • lenRuneCountIntString 函數(shù)具有不同的行為
  • 我們應(yīng)該小心 for 循環(huán)和字符串
  • 字符串相等是我們需要更精確的地方
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末烟瞧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子染簇,更是在濱河造成了極大的恐慌参滴,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锻弓,死亡現(xiàn)場(chǎng)離奇詭異砾赔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)青灼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門暴心,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人杂拨,你說(shuō)我怎么就攤上這事专普。” “怎么了扳躬?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵脆诉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我贷币,道長(zhǎng),這世上最難降的妖魔是什么亏狰? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任役纹,我火速辦了婚禮,結(jié)果婚禮上暇唾,老公的妹妹穿的比我還像新娘促脉。我一直安慰自己,他們只是感情好策州,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布瘸味。 她就那樣靜靜地躺著,像睡著了一般够挂。 火紅的嫁衣襯著肌膚如雪旁仿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天孽糖,我揣著相機(jī)與錄音枯冈,去河邊找鬼毅贮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尘奏,可吹牛的內(nèi)容都是我干的滩褥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼炫加,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瑰煎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起俗孝,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤酒甸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后驹针,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烘挫,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年柬甥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饮六。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苛蒲,死狀恐怖卤橄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情臂外,我是刑警寧澤窟扑,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站漏健,受9級(jí)特大地震影響嚎货,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔫浆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一殖属、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓦盛,春花似錦洗显、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嘱吗,卻和暖如春玄组,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工巧勤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嵌灰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓颅悉,卻偏偏與公主長(zhǎng)得像沽瞭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剩瓶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容