基本數據類型和string之間的轉換
(1) 基本類型轉string
- 使用 fmt.Sprintf(“%參數”, 表達式)
a. 通用:
參數 | 含義 |
---|---|
%v | 值的默認格式表示 |
%+v | 類似%v,但輸出結構體時會添加字段名 |
%#v | 值的Go語法表示 |
%T | 值的類型的Go語法表示 |
%% | 百分號 |
b. 布爾值:
參數 | 含義 |
---|---|
%t | 單詞true或false |
c. 整數:
參數 | 含義 |
---|---|
%b | 表示為二進制 |
%c | 該值對應的unicode碼值 |
%d | 表示為十進制 |
%o | 表示為八進制 |
%q | 該值對應的單引號括起來的go語法字符字面值,必要時會采用安全的轉義表示 |
%x | 表示為十六進制,使用a-f |
%X | 表示為十六進制,使用A-F |
%U | 表示為Unicode格式:U+1234,等價於"U+%04X" |
d. 浮點數與復數的兩個組分:
參數 | 含義 |
---|---|
%b | 無小數部分、二進制指數的科學計數法,如-123456p-78 |
%e | 科學計數法,如 -1234.456e+78 |
%E | 科學計數法,如 -1234.456E+78 |
%f | 有小數部分但無指數部分,如123.456 |
%F | 等價於 %f |
%g | 根據實際情況采用 %e 或 %f 格式(以獲得更簡潔、准確的輸出) |
%G | 根據實際情況采用 %E 或 %F 格式(以獲得更簡潔、准確的輸出) |
e. 字符串和[]byte:
參數 | 含義 |
---|---|
%s | 直接輸出字符串或者 []byte |
%q | 該值對應的雙引號括起來的go語法字符串字面值,必要時會采用安全的轉義表示 |
%x | 每個字節用兩字符十六進制數表示(使用a-f) |
%X | 每個字節用兩字符十六進制數表示(使用A-F) |
f. 指針:
參數 | 含義 |
---|---|
%p | 表示為十六進制,並加上前導的 0x |
狂吐槽,這種方式靈活多變,可以滿足所有要求,但實際上大多數情況下,轉 string 就是想看到一個值原本的樣子,為什么不能每種類型給個默認參數呢?如果有不同需求再傳參啊,就像 .net 里的 ToString() 方法。
- 使用 strconv 包的函數
func FormatBool(b bool) string
func FormatInt(i int64, base int) string
func FormatUint(i uint64, base int) string
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
func Itoa(i int) string // Itoa是FormatInt(i, 10) 的簡寫
base:指定進制(2到36)
fmt:表示格式:'f'(-ddd.dddd)、'b'(-ddddp±ddd,指數為二進制)、'e'(-d.dddde±dd,十進制指數)、'E'(-d.ddddE±dd,十進制指數)、'g'(指數很大時用 'e' 格式,否則 'f' 格式)、'G'(指數很大時用 'E' 格式,否則 'f' 格式)。
prec:精度(排除指數部分):對 'f'、'e'、'E',它表示小數點后的數字個數;對 'g'、'G',它控制總的數字個數。如果 prec 為-1,則代表使用最少數量的、但又必需的數字來表示 f。
bitSize:表示 f 的來源類型(32:float32、64:float64),會據此進行舍入。
繼續狂吐槽,這種方式太二了,參數都是 64 位的,傳個 int32 還不行,必須先強轉成 int64,這不是浪費效率嗎。而且每種參數類型都對應一個方法,方法名還不同,因為,Golang 不支持方法重載。
(2) string 轉基本類型
func ParseInt(s string, base int, bitSize int) (i int64, err error)
func ParseUint(s string, base int, bitSize int) (n uint64, err error)
func ParseFloat(s string, bitSize int) (f float64, err error)
func FormatBool(b bool) string
func Atoi(s string) (i int, err error) // Atoi是ParseInt(s, 10, 0)的簡寫。
base:指定進制(2到36),如果base為0,則會從字符串前置判斷,"0x"是16進制,"0"是8進制,否則是10進制。
bitSize:指定結果必須能無溢出賦值的整數類型,0、8、16、32、64 分別代表 int、int8、int16、int32、int64;簡單的說,如果這個 string 所表示的真實值超出了 baseSize 所指定的類型的范圍,那么就會發生溢出,雖然這個返回值是 64 位的,然並卵,看下面的例子就明白了。
var str string = "999"
var num int64
num, _ = strconv.ParseInt(str, 10, 8)
fmt.Println(num) // 結果是 127
都無力吐槽了。
首先這些方法返回兩個值(Golang 允許函數有多個返回值),第一個是轉換結果,64 位的,如果你需要的是一個 32 位的值,那么還需要強制轉換。
第二個是錯誤信息,如果不想看錯誤信息,可以用 _ (詳見空標識符)忽略。當發生錯誤時,返回的值是默認值 0。這就是說,你沒辦法 try catch 了。
值類型和引用類型
值類型: int、float、string、bool、數組、結構體struct
引用類型:指針、切片slice、map、管道channel、interface
注意:數組也是值類型,跟其他語言不同。
值類型通常在棧中分配,引用類型通常在堆中分配,當沒有任何一個引用指向該引用類型的地址時,GC 將其回收。
這里說的是通常,而不是絕對,這是由於 Golang 中的逃逸機制導致的,這個逃逸機制以后再說。
空標識符
_
是一個特殊的標識符,稱為空標識符。它可以代表其他任何的標識符,但是它對應的值會被忽略,所以僅能作為占位符使用。
訪問級別
Golang 中沒有 public、private 等訪問修飾符,而是規定,常量名、變量名、函數名的首字母如果是大寫的,則可以被其他包訪問,如果是小寫的,則其他包不能訪問。
運算符
(1) 取模
a % b
的運算規則是 a - a / b * b
(2) ++ 和 --
Golang 中,只有 i++
,而沒有 ++i
。
自增和自減只能當做一個獨立的語句使用,j = i++
、if i++ > 0
等寫法都是錯的。
(3) 三元運算符
Golang 不支持三元運算符,請用 if else
。
這個我忍。
if
基本語法:
if 條件表達式 {
語句塊
} else {
語句塊
}
- 條件表達式不需要用
()
括起來,在一般情況下,加了 () 也不會報錯,但是不建議這么做。如果條件表達式用有定義變量(見下文),那么加了 () 會報錯。 - 語句塊必須包含在
{}
中,即便該語句塊中只包含一條語句。(自動加分號導致) else
必須寫在if
語句塊的}
后面,不能另起一行。(自動加分號導致)- 允許在條件表達式中聲明一個變量,以分號結尾,在這個變量后面再寫條件表達式,這個變量的作用域只在該條件邏輯塊內。
if age := 20; age > 18 {
fmt.Println("已成年")
} else {
fmt.Println("未成年")
}
我又要開始吐槽了,在條件表達式里聲明一個變量,看起來不錯。但是,這里的聲明方式,只能用
:=
的方式,不能使用var
關鍵字來聲明,這就意味着你不能顯示給它指定類型,只能是推導出來的默認類型。而前面也已經說過了,Golang 沒有隱式轉換,不同類型之間是無法比較的。

遇到這種情況,如果
n
的類型無法改變,還是只能把age
定義在外面。
最要命的還不是這里,而是在 for 循環里,for 循環里是肯定要定義一個循環變量的,不管是在里面還是外面,然后這問題就少不了了。
switch
基本語法
switch 表達式 {
case 表達式1:
語句塊
case 表達式2, 表達式3,...:
語句塊
default:
語句塊
}
case
后面可以跟多個表達式,逗號隔開,只要其中一個匹配成功就可進入case
的語句塊中不需要加break
,默認情況下,語句塊執行完成后就退出 switchswitch
后可以不帶表達式,類似if else
分支來使用
var age int = 20
switch {
case age > 18:
fmt.Println("已成年")
default:
fmt.Println("未成年")
}
switch
后也可以直接聲明一個變量,以分號結束,和if
類似,但這種寫法不推薦使用。
switch age := 20; {
case age > 18:
fmt.Println("已成年")
default:
fmt.Println("未成年")
}
- switch 穿透:在
case
語句塊后增加fallthrough
,則會執行下一個case
。只能穿透一層case
。 switch
語句還可以被用於 type-switch 來判斷某個interface
變量中實際指向的變量類型。
for循環
基本語法:
for i := 1 ; i < 10; i++ {
語句塊
}
也可以將循環變量定義或循環變量迭代寫在其他地方,但分號不能省略,這點跟 .net 等語言是一樣的。
i := 1
for ;i < 10; i++ {
語句塊
}
第二種寫法,for 后面可以僅有循環條件判斷
i := 1
for i < 10 {
語句塊
i++
}
第三種寫法:
for {
語句塊
}
這種寫法等價於for ; ; {}
,是一個死循環,通常需要配合 break
使用。
Golang 中沒有 while 和 do while,如果要實現類似的效果,就只能用這個方式。
for range
for range
方式用於遍歷容器類型,如字符串、數組、切片、映射。
var str string = "hello"
for index, value := range str {
fmt.Printf("%v %c\n", index, value)
}
for range
遍歷字符串的時候是按字節的方式遍歷的,看如下示例:
var str1 string = "hello 北京"
for index, value := range str1 {
fmt.Printf("%v %c\n", index, value)
}
//運行結果
0 h
1 e
2 l
3 l
4 o
5
6 北
9 京 //注意這里 index 從 6 直接跳到了 9,因為 UTF-8 編碼一個漢字占 3 個字節
break 和 continue
break
用於跳出循環,在 .net 等語言中,break
只能用於跳出當前循環,而在 Golang 中,可以通過標簽指明要跳出哪一層的循環。有點類似 goto
了。
lable1:
for i := 0; i < 10; i++{
for j := 0; j < 10; j ++{
if j == 2{
break lable1
}
fmt.Println(j)
}
}
continue
和 break
一樣,也可以通過標簽指定要繼續的是哪一層循環。