01
介紹
關于 Go 語言字符串的使用,我們需要了解標準庫 strconv
和標準庫 strings
的使用方式,它們分別用于字符串類型轉換和字符串操作。
本文我們重點介紹 Go 語言字符串使用方式與技巧。
02
字符串類型轉換
Go 語言是強類型語言,在使用 Go 語言時,通常會遇到需要將字符串與其它類型相互轉換的場景。
此時,我們可以使用標準庫 strconv
。
字符串 to 布爾
示例代碼:
func mAIn() {
v := "true"
if s, err := strconv.ParseBool(v); err == nil {
fmt.Printf("%T, %vn", s, s)
}
}
輸出結果:
bool, true
閱讀上面這段代碼,我們使用 func ParseBool(str string) (bool, error)
將字符串轉換為布爾。需要注意的是,該函數接收參數的值是有限制的,除了 1、t、T、TRUE、true、True、0、f、F、FALSE、false、False 之外,其它任何值都會返回 error。
字符串 to 浮點型
示例代碼:
func main() {
v := "3.1415926535"
if s, err := strconv.ParseFloat(v, 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat(v, 64); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("NaN", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
// ParseFloat is case insensitive
if s, err := strconv.ParseFloat("nan", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("inf", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("+Inf", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("-Inf", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("-0", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
if s, err := strconv.ParseFloat("+0", 32); err == nil {
fmt.Printf("%T, %vn", s, s)
}
}
輸出結果:
float64, 3.1415927410125732
float64, 3.1415926535
float64, NaN
float64, NaN
float64, +Inf
float64, +Inf
float64, -Inf
float64, -0
float64, 0
閱讀上面這段代碼,我們使用 func ParseFloat(s string, bitSize int) (float64, error)
將字符串轉換為 64 位浮點數。需要注意的是,該函數接收參數可以識別值為 NaN
、Inf
(有符號 +Inf
或 -Inf
),并且忽略它們的大小寫。
字符串 to 整型
示例代碼:
func main() {
v32 := "-354634382"
if s, err := strconv.ParseInt(v32, 10, 32); err == nil {
fmt.Printf("s:%T, %vn", s, s)
}
if s1, err := strconv.ParseInt(v32, 16, 32); err == nil {
fmt.Printf("s1:%T, %vn", s1, s1)
}
v64 := "-3546343826724305832"
if s2, err := strconv.ParseInt(v64, 10, 64); err == nil {
fmt.Printf("s2:%T, %vn", s2, s2)
}
if s3, err := strconv.ParseInt(v64, 16, 64); err == nil {
fmt.Printf("s3:%T, %vn", s3, s3)
}
}
輸出結果:
s:int64, -354634382
s2:int64, -3546343826724305832
閱讀上面這段代碼,我們使用 func ParseInt(s string, base int, bitSize int) (i int64, err error)
將字符串轉換為整型。
需要注意的是,該函數的第一個入參為字符串類型的數值,可以 "+" 或 "-" 符號開頭;
第二個參數指定進制,它的值如果是 0
,進制則以第一個參數符號后的前綴決定,例如:"0b" 為 2,"0" 或 "0o" 為 8,"0x" 為 16,否則為 10;
第三個參數指定返回結果必須符合整數類型的取值范圍,它的值為 0、8、16、32 和 64,分別代表 int
、int8
、int16
、int32
和 int64
。
細心的讀者朋友們可能已經發現,示例代碼中,第 2 和 第 4 返回錯誤,原因是第二個參數指定的進制與第一個參數的數值不相符,超出取值范圍。
此外,函數 func ParseUint(s string, base int, bitSize int) (uint64, error)
與之類似,但是用于無符號整數。
在實際項目開發中,十進制使用的最多,所以標準庫 strconv
提供了函數 func Atoi(s string) (int, error)
,它的功能類似 ParseInt(s, 10, 0)
,需要注意的是,它的返回值類型是 int
(需要注意取值范圍),而不是 int64
。
布爾 to 字符串
示例代碼:
func main() {
v := true
s := strconv.FormatBool(v)
fmt.Printf("%T, %vn", s, s)
}
輸出結果:
string, true
閱讀上面這段代碼,我們使用 func FormatBool(b bool) string
將布爾轉換為字符串。
浮點型 to 字符串
示例代碼:
func main() {
v := 3.1415926535
s32 := strconv.FormatFloat(v, 'E', -1, 32)
fmt.Printf("%T, %vn", s32, s32)
s64 := strconv.FormatFloat(v, 'E', -1, 64)
fmt.Printf("%T, %vn", s64, s64)
fmt64 := strconv.FormatFloat(v, 'g', -1, 64)
fmt.Printf("%T, %vn", fmt64, fmt64)
}
輸出結果:
string, 3.1415927E+00
string, 3.1415926535E+00
string, 3.1415926535
閱讀上面這段代碼,我們使用 func FormatFloat(f float64, fmt byte, prec, bitSize int) string
將浮點型轉換為字符串。該函數包含 4 個參數,第一個參數是需要轉換的浮點數;第二個參數是進制;第三個參數是精度,第四個參數是轉換后值的取值范圍。
其中,第二個參數 b
代表二進制指數;e
或 E
代表十進制指數;f
代表無進制指數;g
或 G
代表指數大時 為 e
,反之為 f
;x
或 X
代表十六進制分數和二進制指數。
第三個參數,精度 prec 控制由 'e','E','f','g','G','x' 和 'X' 格式打印的位數(不包括指數)。對于 'e','E','f','x' 和 'X',它是小數點后的位數。對于 'g' 和 'G',它是有效數字的最大數目(去掉后面的零)。特殊精度 -1 使用所需的最小位數,以便 ParseFloat 精確返回 f
。
整型 to 字符串
示例代碼:
func main() {
v := int64(-42)
s10 := strconv.FormatInt(v, 10)
fmt.Printf("%T, %vn", s10, s10)
s16 := strconv.FormatInt(v, 16)
fmt.Printf("%T, %vn", s16, s16)
}
輸出結果:
string, -42
string, -2a
閱讀上面這段代碼,我們使用 func FormatInt(i int64, base int) string
將整型轉換為字符串。需要注意的是,第二個參數的取值范圍 2 <= base <= 36
。
此外,函數 func FormatUint(i uint64, base int) string
與之功能類型,區別是僅用于轉換無類型整數。
在實際項目開發中,十進制使用的最多,所以標準庫 strconv
提供了函數 func Itoa(i int) string
,它的功能類似 FormatInt(int64(i), 10)
,需要注意的是,該函數入參的類型是 int
。
03
字符串操作
關于字符串操作,標準庫 strings
提供了相關函數,我們介紹幾個常用的函數。
字符串中是否包含指定字符串
示例代碼:
func main() {
fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
fmt.Println(strings.Contains("seafood", ""))
fmt.Println(strings.Contains("", ""))
}
輸出結果:
true
false
true
true
閱讀上面這段代碼,我們使用 func Contains(s, substr string) bool
在字符串 substr
中查找 s
,存在則返回 true
,反之返回 false
。
字符串中是否包含指定字符串中任意字符
示例代碼:
func main() {
fmt.Println(strings.ContainsAny("team", "i"))
fmt.Println(strings.ContainsAny("fail", "ui"))
fmt.Println(strings.ContainsAny("ure", "ui"))
fmt.Println(strings.ContainsAny("failure", "ui"))
fmt.Println(strings.ContainsAny("foo", ""))
fmt.Println(strings.ContainsAny("", ""))
}
輸出結果:
false
true
true
true
false
false
閱讀上面這段代碼,我們使用 func ContainsAny(s, chars string) bool
在字符串 s
中查找是否包含字符串 chars
中任意字符,存在則返回 true
,反之返回 false
。
刪除字符串中指定字符
示例代碼:
func main() {
fmt.Print(strings.Trim("¡¡¡Hello, Gophers!!!", "!¡"))
}
輸出結果:
Hello, Gophers
閱讀上面這段代碼,我們使用 func Trim(s, cutset string) string
刪除字符串 s
中的字符 cutset
。
字符串轉換為大寫
示例代碼:
func main() {
fmt.Println(strings.ToUpper("Gopher"))
}
輸出結果:
GOPHER
閱讀上面這段代碼,我們使用 func ToUpper(s string) string
將字符串中的字符全部轉換為大寫。
字符串以指定字符拆分為字符串切片
示例代碼:
func main() {
fmt.Printf("%qn", strings.Split("a,b,c", ","))
fmt.Printf("%qn", strings.Split("a man a plan a canal panama", "a "))
fmt.Printf("%qn", strings.Split(" xyz ", ""))
fmt.Printf("%qn", strings.Split("", "Bernardo O'Higgins"))
}
輸出結果:
["a" "b" "c"]
["" "man " "plan " "canal panama"]
[" " "x" "y" "z" " "]
[""]
閱讀上面這段代碼,我們使用 func Split(s, sep string) []string
將字符串 s
以字符串 sep
為分隔符,拆分為字符串切片。
字符串切片拼接為字符串
示例代碼:
func main() {
s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))
}
輸出結果:
foo, bar, baz
閱讀上面這段代碼,我們使用 func Join(elems []string, sep string) string
將字符串切片中的所有元素,以 sep
為分隔符,拼接為字符串。
04
字符串拼接
關于字符串拼接,分為編譯時字符串拼接,和運行時字符串拼接。
其中,編譯時字符串拼接,即使用 +
將多個字符串拼接為一個字符串,需要注意的是,在使用 +
拼接字符串時,如果存在字符串變量,則會在運行時拼接。
示例代碼:
func main() {
str := "hello" + " world"
fmt.Println(str)
name := "frank"
outPut := "My name is " + name
fmt.Println(outPut)
}
輸出結果:
hello world
My name is frank
閱讀上面這段代碼,第一個字符串拼接是在編譯時拼接,第二個字符串拼接是在運行時拼接。
需要注意的是,運行時拼接是分配一塊新的內存空間,通過內存拷貝的方式將字符串拷貝到新內存空間。
如果拼接后的字符串小于 32 字節,可以使用臨時緩存;如果拼接后的字符串大于 32 字節,需要在堆區分配一塊內存空間,并將需要拼接的多個字符串通過內存拷貝的形式拷貝過去。
字符串與字節數組互相轉換時,也需要通過內存拷貝的方式,如果字符串大于 32 字節,需要在堆區分配一塊內存空間,所以在一些轉換密集的場景,我們需要特別注意。
此外,除了使用操作符 +
或 +=
拼接字符串之外,還有多種字符串拼接方式,例如,fmt.Sprintf
、bytes.Buffer
、strings.Join
和 stings.Builder
。這些字符串拼接方式在之前的文章 「Golang 語言怎么高效拼接字符串?」 介紹過,本文不再贅述。
05
總結
本文我們介紹 Go 語言中字符串的使用方式,包括類型轉換、字符串操作、字符串拼接。
除了使用標準庫 strconv
進行字符串類型轉換之外,讀者朋友們也可以選擇三方庫,例如:Github.com/spf13/cast
。
建議讀者朋友們閱讀標準庫文檔,了解更多關于標準庫 strconv
和 strings
的函數。