1. 程式人生 > >golang基礎教程——字串篇

golang基礎教程——字串篇

本文始發於個人公眾號:**TechFlow**,原創不易,求個關注

今天是golang專題的第6篇文章,這篇主要和大家聊聊golang當中的字串的使用。

字串定義

golang當中的字串本質是隻讀的字元型陣列,和C語言當中的char[]類似,但是golang為它封裝了一個變數型別,叫做string。知道了string這個型別之後,我們就可以很方便地來初始化:

var str string
str1 := "hello world"
var str2 = "hello world too"

這裡應該沒什麼難度,很好理解。由於這個陣列是隻讀的,所以我們可以通過下標獲取某一位的字元,但是不允許修改。

// 允許
fmt.Println(str1[3])

// 錯誤
str1[3] = 'l'

這個也不是golang的獨創,很多語言當中都有這個限制,因為會將字串作為const型別儲存在專門的區域。所以不允許字串進行修改,比如Python也是如此。

除了像是陣列一樣,支援下標的訪問之外,go中的字串還支援拼接以及求長度的操作。我們可以用len函式獲取一個字串的長度,用+來表示字串的拼接:

len("hello")
// 5

c := "hello" + "world"
// c="helloworld"

這些本來也屬於常規操作,並不值得一提,但是關於len函式,值得仔細說說。這裡有一個坑,關於utf-8編碼。我們來看下面這個例子:

str := "hello 世界"
fmt.Println(len(str))

按照我們的設想,它返回的應該是8,但是實際上我們這麼操作會得到12。原因很簡單,因為在utf-8編碼當中,一個漢字需要3個位元組編碼。那如果我們想要得到字串本身的長度,而不是字串佔據的位元組數,應該怎麼辦呢?這個時候,我們需要用到一個新的結構叫做rune,它表示單個Unicode字元。

所以我們可以將string轉化成rune陣列,之後再來計算長度,得到的結果就準確了。

str := "hello 世界"
fmt.Println(len([]rune(str)))

這樣我們得到的結果就是8了,和我們預期一致了。如果你在使用golang的時候,需要用到utf-8編碼,一定要小心。

型別轉換

golang當中的字串不像Java或者其他語言一樣封裝地非常完善,當我們想要將整形或者是浮點型轉成字串,或者是想要將字串轉成整形和浮點型的時候並沒有方法可以直接呼叫,而必須要通過庫函式。golang當中提供了strconv庫,用來實現字串的一些操作。

字串轉整數、浮點數

字串轉整數的方法有兩個,一個是ParseInt還有一個是ParseUint,這兩個方法本質上都是將字串轉成整數。區別在於前者會保留符號,後者是無符號的,用於無符號整數。

這兩個函式都接受三個引數,第一個引數是要轉型別的字串,第二個引數int的進位制,比如二進位制、八進位制還是16進位制、32進位制。第三個引數表示返回bit的大小,有效值為0,8,16,32,64,如果傳入0就返回int或者是uint型別,如果是32,則會返回int32型別。

函式的返回值有兩個,第一個是型別轉換之後的結果,第二個是一個error,也就是異常型別,表示在轉換的過程當中是否有出現異常。如果沒有異常,那麼這個值會是一個nil。我們判斷異常是否是nil就知道有無錯誤產生,這也是golang當中判斷操作有沒有異常的常規做法。

所以,程式碼寫出來會是這樣的:

value, err := strconv.ParseInt("33225", 10, 32)
if err != nil {
  fmt.Println("error happens")
}

如果你不想要這麼多功能,就想簡單一點將字串轉成int來使用,也可以通過Atoi函式。相比於ParseInt它要簡單一些, 只需要傳入字串即可,它預設按照10進位制進行轉換,並且轉換之後會返回int型別的整數。

value, err := strconv.Atoi("33234")
if err != nil {
  fmt.Println("error happens")
}

字串轉浮點數只有一個函式,就是ParseFloat,由於浮點數沒有進位制一說,所以它只有兩個引數。第一個引數是待轉的字串,第二個引數是bit的大小。和ParseInt一樣,它會返回兩個結果,一個是轉換之後的結果,一個是error異常。

value, err := strconv.ParseFloat("33.33", 32)
if err != nil {
  fmt.Println("error happens")
}

整數、浮點數轉字串

將整數和浮點數轉字串都是用Format方法,根據我們要轉的型別不同,分為FormatInt和FormatFloat。FormatInt可以認為是ParseInt的逆向操作,我們固定傳入一個int64的型別,和整數的進位制。golang會根據我們的數字和進位制,將它轉成我們需要的字串。

如果指定的進位制超過10進位制,那麼會使用a-z字母來表示大於10的數字。

比如我們把180轉成16進位制,會得到b4

num := 180
fmt.Println(strconv.FormatInt(int64(num), 16))

如果我們固定要按照10進位制的整數進行轉換,golang還為我們提供了簡化的函式Itoa,預設按照10進位制轉化,它等價於FormatInt(i, 10),這樣我們只需要傳入一個值即可。

num := 180
fmt.Println(strconv.Itoa(num))

浮點數轉字串邏輯大同小異,但是傳參稍有變化。因為浮點數可以用多種方式來表示,比如科學記數法或者是十進位制指數法等等。golang當中支援了這些格式,所以允許我們通過傳入引數來指定我們希望得到的字串的格式。

FormatFloat接受4個引數,第一個引數就是待轉換的浮點數,第二個引數表示我們希望轉換之後得到的格式。一共有'f', 'b', 'e', 'E', 'g', 'G'這幾種格式。

看起來有些眼花繚亂,我們仔細說說。

'f' 表示普通模式:(-ddd.dddd)

'b' 表示指數為二進位制:(-ddddp±ddd)

'e' 表示十進位制指數,也就是科學記數法的模式:(-d.dddde±dd)

'E' 和'e'一樣,都是科學記數法的模式,只不過字母e大寫:(-d.ddddE±dd)

'g' 表示指數很大時用'e'模式,否則用‘f'模式

'G' 表示指數很大時用’E'模式,否則用'f'模式

我們來看個例子:

num := 23423134.323422
fmt.Println(strconv.FormatFloat(float64(num), 'f', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'b', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'e', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'E', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'g', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'G', -1, 64))

得到的結果如下:

字串和bool型轉換

除了常用的整數和浮點數之外,strconv還支援與bool型別進行轉換。

其中將字串轉成bool型別用的是ParseBool,它只有一個引數,只接受0, 1, t, f, T, F, ture, false, True, False, TRUE, FALSE這幾種取值,否則會返回錯誤。

flag, err := strconv.ParseBool('t')
if err != nil {
  fmt.Println("error happens")
}

將bool轉字串呼叫FormatBool方法,它也只有一個引數,就是一個bool型別的變數,返回值也是確定的,如果是True就返回"true", 如果是False就返回"false"。

fmt.Println(strconv.FormatBool(true))

字串運算包

前面介紹的strconv包是golang當中字串的一個轉換操作包,可以用來將字串轉成其他型別,將其他型別轉化成字串。關於字串本身的一些操作,還有一個專門的包叫做strings。

字串比較

我們可以通過strings.Compare來比較兩個字串的大小,這個函式類似於C語言當中的strcmp,會返回一個int。

cmp := strings.Compare(str1, str2)

cmp等於-1表示str1字典序小於str2,如果str1和str2相等,cmp等於0。如果cmp=1,表示str1字典序大於str2.

查詢函式

我們可以用Index函式查詢一個字串中子串的位置,它會返回第一次出現的位置,如果不存在返回-1.

var theInd = strings.Index(str, "sub")

類似的方法是LastIndex,它返回的是出現的最後一個位置,同樣,如果不存在返回-1.

var theLastIdx = strings.LastIndex(str, "last")

Count和Repeat

我們可以用Count來統計子串在整體當中出現的次數。

strings.Count("abcabcabababc", "abc") 

第一個引數是母串,第二個引數是子串。如果子串為空,則返回母串的長度+1.

有count自然就有重複,我們可以用Repeat方法來講字串重複指定的次數:

repeat := strings.Repeat("abc", 10)

Replace、Split和Join

還有Replace函式,可以替換字串中的部分。這個函式接收四個引數,分別是字串,匹配串和目標串,還有替換的次數。如果小於0,表示全部替換。

str := "aaaddc"

strings.Replace(str, "a", "b", 1) // baaddc
strings.Replace(str, "a", "b", -1)

我們還可以通過Split方法來分割字串,它的使用方法和Python當中的split一樣,我們傳入字串與分隔符,會返回根據分隔符分割之後的字串陣列:

str := "abc,bbc,bbd"

slice := strings.Split(str, ",")

除了Split之外,我們也經常使用它的逆操作也就是Join。通過我們指定的分隔符,將一個字串陣列拼接在一起。

slice := []string{"aab", "aba", "baa"}
str := strings.Join(slice, ",")

strings當中的函式除了剛才列舉的之外還有很多,比如用來去除字串首尾多餘字元的Trim和TrimLeft,判斷是否包含字首的HasPrefix和判斷是否包含字尾的HasSufix等等,由於篇幅限制,不一一列舉了,大家用到的時候可以查閱strings的api文件。

總結

到這裡,關於golang當中string的一些基本用法就介紹完了。一般來說,我們日常需要用到的功能,strings和strconv這兩個庫就足夠使用了。初學者可能經常會把這兩個庫搞混淆,其實很容易分清,strings當中封裝的是操作字串的一些函式。比如字串判斷、join、split等各種處理,而strconv是專門用來字串和其他型別進行轉換的,除此之外基本上沒有其他的功能。牢記這兩點之後,很容易區分開。

今天介紹的api有些多,如果記不過來也沒有關係, 我們只需要大概有一個印象即可,具體可以使用到的時候再去查閱相關的資料。

如果覺得有所收穫,請給我一個關注。

![](https://user-gold-cdn.xitu.io/2020/5/25/17249bf2c65334b3?w=258&h=258&f=png&