1. Go語(yǔ)言數(shù)據(jù)類(lèi)型
1.1 數(shù)據(jù)類(lèi)型分類(lèi)
Go語(yǔ)言數(shù)據(jù)類(lèi)型大致可以分為兩類(lèi)
基礎(chǔ)類(lèi)型,其中就包括了我們最常見(jiàn)的一些類(lèi)型
類(lèi)型 名稱(chēng) 長(zhǎng)度 零值 說(shuō)明 bool 布爾類(lèi)型 1 false 其值不為真即為家,不可以用數(shù)字代表true或false byte 字節(jié)型 1 0 uint8別名 rune 字符類(lèi)型 4 0 專(zhuān)用于存儲(chǔ)unicode編碼,等價(jià)于uint32 int, uint 整型 4或8 0 32位或64位 int8, uint8 整型 1 0 -128 ~ 127, 0 ~ 255 int16, uint16 整型 2 0 -32768 ~ 32767, 0 ~ 65535 int32, uint32 整型 4 0 -21億 ~ 21 億, 0 ~ 42 億 int64, uint64 整型 8 0 float32 浮點(diǎn)型 4 0.0 小數(shù)位精確到7位 float64 浮點(diǎn)型 8 0.0 小數(shù)位精確到15位 complex64 復(fù)數(shù)類(lèi)型 8 complex128 復(fù)數(shù)類(lèi)型 16 uintptr 整型 4或8 ?以存儲(chǔ)指針的uint32或uint64整數(shù) string 字符串 "" utf-8字符串 復(fù)合類(lèi)型, 這些類(lèi)型構(gòu)成了Go語(yǔ)言的特點(diǎn)
- 指針 (pointer)
- 數(shù)字 (array)
- 切片 (slice)
- 字典(map)
- 通道 (chan)
- 結(jié)構(gòu)體 (struct)
- 接口 (interface)
2. 布爾類(lèi)型
- 也叫做bool類(lèi)型
- bool 類(lèi)型數(shù)據(jù)的值只能是true 或者 false
- bool 類(lèi)型默認(rèn)值是false
- bool 類(lèi)型 占1個(gè)字節(jié)
- bool類(lèi)型一般用于流程控制
- bool類(lèi)型不能接受其他類(lèi)型賦值
- bool類(lèi)型不支持自動(dòng)或者強(qiáng)制類(lèi)型裝換
package main
import "fmt"
var a bool
func main() {
//a = 1 // 錯(cuò)誤 cannot use 1 (type int) as type bool in assignment
fmt.Printf("type = %T\n", a)
fmt.Printf("value = %v\n", a)
if a {
fmt.Println("this is true")
} else {
fmt.Println("this is false")
}
}
type = bool
value = false
this is false
3. 整數(shù)類(lèi)型
整數(shù)類(lèi)型就是存放整數(shù)值得
int類(lèi)型和uint類(lèi)型自動(dòng)匹配平臺(tái)長(zhǎng)度
類(lèi)型 有無(wú)符號(hào) 占用空間 范圍 備注 int 有 32位系統(tǒng)4個(gè)字節(jié)<br />64位系統(tǒng)8個(gè)字節(jié) <br />
![]()
uint 無(wú) 32位系統(tǒng)4個(gè)字節(jié)<br />64位系統(tǒng)8個(gè)字節(jié) <br />
![]()
rune 有 與int32一樣 等價(jià)int32,表示一個(gè)Unicode碼 byte 無(wú) 與uint8等價(jià) 0~255 存儲(chǔ)字符使用 Go語(yǔ)言的整型默認(rèn)聲明是int型
通常int和int32被認(rèn)為是兩種不同的類(lèi)型,編譯器不會(huì)做自動(dòng)裝換
整數(shù)類(lèi)型可以進(jìn)行數(shù)值運(yùn)算 (加減乘除和求余)
整數(shù)類(lèi)型可以進(jìn)行比較運(yùn)算(> , < ,==, >= , <= ,!=)
兩個(gè)不同類(lèi)型的整數(shù)不能比較,即使他們的值看著相同也不行
3.1 查詢(xún)某個(gè)變量的字節(jié)大小和數(shù)據(jù)類(lèi)型
package main
import (
"fmt"
"unsafe"
)
var v1 int8
var v2 int16 = 88
var v3 int32 = 8978923
var v4 = 8978989
var v5 int64
var v6 rune
func main(){
fmt.Printf("v1 類(lèi)型是%T, v1 占的字節(jié)數(shù)是%d\n",v1,unsafe.Sizeof(v1))
fmt.Printf("v2 類(lèi)型是%T, v2 占的字節(jié)數(shù)是%d\n",v2,unsafe.Sizeof(v2))
fmt.Printf("v3 類(lèi)型是%T, v3 占的字節(jié)數(shù)是%d\n",v3,unsafe.Sizeof(v3))
fmt.Printf("v4 類(lèi)型是%T, v4 占的字節(jié)數(shù)是%d\n",v4,unsafe.Sizeof(v4))
fmt.Printf("v5 類(lèi)型是%T, v5 占的字節(jié)數(shù)是%d\n",v5,unsafe.Sizeof(v5))
fmt.Printf("v6 類(lèi)型是%T, v6 占的字節(jié)數(shù)是%d\n",v6,unsafe.Sizeof(v6))
}
v1 類(lèi)型是int8, v1 占的字節(jié)數(shù)是1
v2 類(lèi)型是int16, v2 占的字節(jié)數(shù)是2
v3 類(lèi)型是int32, v3 占的字節(jié)數(shù)是4
v4 類(lèi)型是int, v4 占的字節(jié)數(shù)是8
v5 類(lèi)型是int64, v5 占的字節(jié)數(shù)是8
v6 類(lèi)型是int32, v6 占的字節(jié)數(shù)是4
3.2 如何證明int和int64不是同一種類(lèi)型
package main
import (
"fmt"
"unsafe"
)
var v1 = 99
var v2 int64
func main(){
fmt.Printf("v1的類(lèi)型是%T,v1占的字節(jié)長(zhǎng)度是%d\n",v1,unsafe.Sizeof(v1))
fmt.Printf("v2的類(lèi)型是%T,v2占的字節(jié)長(zhǎng)度是%d\n",v2,unsafe.Sizeof(v2))
// 將v1的值賦給v2
//v2 = v1 // 錯(cuò)誤 cannot use v1 (type int) as type int64 in assignment
v2 = int64(v1) // 通過(guò)
fmt.Printf("v2的值是%v,v2的類(lèi)型是%T",v2,v2)
}
v1的類(lèi)型是int,v1占的字節(jié)長(zhǎng)度是8
v2的類(lèi)型是int64,v2占的字節(jié)長(zhǎng)度是8
v2的值是99,v2的類(lèi)型是int64
3.3 不同的整數(shù)類(lèi)型不能比較
package main
import "fmt"
var a int32
var b int64
func main(){
a,b=8,8
if a == b{ //invalid operation: a == b (mismatched types int32 and int64)
fmt.Println("===")
}
}
4. 浮點(diǎn)型
浮點(diǎn)型用于表示包含小數(shù)點(diǎn)的數(shù)據(jù),例如 1.234 , 0.99 , -9.9等就是一個(gè)浮點(diǎn)型數(shù)據(jù),Go語(yǔ)言中的浮點(diǎn)型采用 IEEE-754 標(biāo)準(zhǔn)的表達(dá)方式
Go語(yǔ)言定義兩個(gè)浮點(diǎn)類(lèi)型float32和float64,其中float32相當(dāng)于C語(yǔ)言中的float類(lèi)型, float64等價(jià)于C語(yǔ)言中的double類(lèi)型
類(lèi)型 占用存儲(chǔ)空間 范圍 單精度f(wàn)loat32 4字節(jié) -3.4028234663852886e+38~3.4028234663852886e+38 雙精度f(wàn)loat64 8字節(jié) -1.7976931348623157e+308~1.7976931348623157e+308
4.1 浮點(diǎn)數(shù) = 符號(hào)位+指數(shù)位+尾數(shù)位
4.2 浮點(diǎn)數(shù)都是有符號(hào)的
package main
import "fmt"
func main(){
var p float32 = 99.99
fmt.Println(p)
var p1 float32 = -0.33
fmt.Println(p1)
var p2 float64 = -79787878.9
fmt.Println(p2)
}
99.99
-0.33
-7.97878789e+07
4.3 float64 比f(wàn)loat32準(zhǔn)確
小數(shù)部分可能丟失,造成精度損失,要保存高精度的數(shù)應(yīng)該選擇float64
Go語(yǔ)言的浮點(diǎn)型默認(rèn)是float64類(lèi)型
package main
import "fmt"
func main(){
var p1 float32 = 897.0000023
var p2 float64 = 897.0000023
fmt.Println("p1 = ",p1)
fmt.Println("p2 = ",p2)
p3 := -12.90
// GO語(yǔ)言默認(rèn)是使用float64類(lèi)型
fmt.Printf("p3 type = %T",p3)
}
p1 = 897
p2 = 897.0000023
p3 type = float64
4.4 浮點(diǎn)是強(qiáng)制轉(zhuǎn)換
需要說(shuō)明float32 和 float64 是兩種類(lèi)型,不能直接相互賦值
package main
import "fmt"
var f1 float32
var f2 float64
func main() {
f2 = 1212.09
fmt.Printf("f2 type is %T, value is %v\n",f2,f2)
// 運(yùn)行報(bào)錯(cuò)
//cannot use f2 (type float64) as type float32 in assignment
f1 = f2
fmt.Printf("f1 type is %T, value is %v\n",f1,f1)
}
我們看看浮點(diǎn)數(shù)float32 和 float64類(lèi)型怎么轉(zhuǎn)換
package main
import "fmt"
var f1 float32
var f2 float64
func main() {
f2 = 1212.09
fmt.Printf("f2 type is %T, value is %v\n",f2,f2)
// 強(qiáng)制轉(zhuǎn)換成float32類(lèi)型
f1 = float32(f2)
fmt.Printf("f1 type is %T, value is %v\n",f1,f1)
}
f2 type is float64, value is 1212.09
f1 type is float32, value is 1212.09
5. 字符類(lèi)型
Go語(yǔ)言中支持兩種字符類(lèi)型 分別是byte 和 rune
byte型 ,實(shí)際上是uint8類(lèi)型的別稱(chēng),代表了ASCII碼的一個(gè)字符
rune 類(lèi)型,代表一個(gè)unicode 字符 ,實(shí)際是一個(gè)int32類(lèi)型,在處理中文,日文或者其他符合類(lèi)型時(shí)需要用到,Go語(yǔ)言中使用特殊的rune類(lèi)型來(lái)處理Unicode,讓基于Unicode的文本處理更為方便
package main import "fmt" func main() { var a byte = 'a' var b rune = '中' // a的值`a`對(duì)應(yīng)的ASCII編碼是97 實(shí)際類(lèi)型是uint8 fmt.Printf("a value = %d type = %T\n", a, a) // b的值`中`對(duì)應(yīng)的Unicode碼是20013 實(shí)際類(lèi)型是int32 fmt.Printf("b value = %d type = %T\n", b, b) // 輸出對(duì)應(yīng)的字符 fmt.Printf("a = %c b = %c",a,b) }
a value = 97 type = uint8 b value = 20013 type = int32 a = a b = 中
Unicode 是字符集,ASCII 也是一種字符集,UTF-8是一種編碼規(guī)則
字符集為每一個(gè)字符分配一個(gè)唯一的ID,我們使用的所有字符在unicode字符集中都有唯一的ID對(duì)應(yīng).
utf-8 是編碼規(guī)則,將unicode字符集中的ID以某種形式進(jìn)行編碼
在Go語(yǔ)言中,字符的本質(zhì)是一個(gè)數(shù)字,格式化輸出時(shí)%c,會(huì)輸出該數(shù)字對(duì)應(yīng)的unicode字符
package main import "fmt" func main(){ var v1 int8 = 102 fmt.Printf("v1 = %c\n",v1) var v2 int = 22381 fmt.Printf("v2 = %c\n",v2) }
v1 = f v2 = 坭
字符串是可以進(jìn)行運(yùn)算的
package main import "fmt" func main() { var v1 int = 10 v1 += 97 fmt.Printf("v1 = %d,unicode = %c",v1,v1) }
v1 = 107,unicode = k
6. string類(lèi)型
Go語(yǔ)言字符串?dāng)?shù)據(jù)對(duì)應(yīng)的字節(jié)數(shù)組,字符串的只讀屬性禁止了在程序中對(duì)底層字節(jié)數(shù)組的元素修改,字符串賦值只是賦值了數(shù)據(jù)地址和對(duì)應(yīng)長(zhǎng)度,而不會(huì)底層數(shù)據(jù)的賦值
字符串是一串固定長(zhǎng)度的字符連接起來(lái)的字符序列,Go語(yǔ)言的字符串的字節(jié)使用utf-8編碼標(biāo)識(shí)的unicode文本
字符串類(lèi)型也就是string類(lèi)型定義很簡(jiǎn)單
package main
import "fmt"
var s1 string
func main() {
s1 = "Celtic 凱爾特人"
s2 := "Lakers 湖人"
var s3 string = "Rocket 火箭"
fmt.Printf("s1 = %s type = %T\n",s1,s1)
fmt.Printf("s2 = %s type = %T\n",s2,s2)
fmt.Printf("s3 = %s type = %T\n",s3,s3)
}
s1 = Celtic 凱爾特人 type = string
s2 = Lakers 湖人 type = string
s3 = Rocket 火箭 type = string
字符串的內(nèi)容可以用類(lèi)似數(shù)組下標(biāo)的方式獲取,但是與數(shù)組不同的是,字符串的內(nèi)容不能在初始化之后修改
package main
import "fmt"
func main() {
var s1 string = "hello world ~~"
// 使用內(nèi)置函數(shù)len()獲取字符串長(zhǎng)度
l := len(s1)
fmt.Printf("s1 的長(zhǎng)度是 : %d\n",l)
// 獲取第一個(gè)字符
ch1 := s1[8]
fmt.Printf("%c ch1 = %v,type = %T\n",ch1,ch1,ch1)
}
s1 的長(zhǎng)度是 : 14
r ch1 = 114,type = uint8
看一個(gè)錯(cuò)誤的例子
package main
import "fmt"
func main() {
var s1 string = "hello world ~~"
//會(huì)報(bào)編譯錯(cuò)誤
s1[0] = "H"
fmt.Println(s1[0])
}
cannot assign to s1[0]
字符串的兩種表示形式
- 雙引號(hào) ,字符串的值在書(shū)寫(xiě)在雙引號(hào)中是最常見(jiàn)的表達(dá)方式,也稱(chēng)為字符串字面量,這種形式不能跨行,如果字符串太長(zhǎng),可以使用 + 拼接
- 反引號(hào), 以字符串原生樣式輸出,包括換行和特殊字符
package main
import "fmt"
func main() {
s0 := "hello" +
"world"
s0 += "\n 中國(guó)"
fmt.Println(s0)
}
helloworld
中國(guó)
package main
import "fmt"
func main() {
// 定義多行字符串
var s1 string = `怒發(fā)沖冠
憑欄處瀟瀟雨歇
抬望眼
仰天長(zhǎng)嘯`
fmt.Println(s1)
}
怒發(fā)沖冠
憑欄處瀟瀟雨歇
抬望眼
仰天長(zhǎng)嘯
以字節(jié)數(shù)組方式遍歷數(shù)組
package main
import "fmt"
func main(){
var s1 string = "golang 中國(guó)"
// 因?yàn)樽址?個(gè)字節(jié),漢字占3個(gè)字節(jié) 所以參數(shù)s1的長(zhǎng)度是13
l := len(s1)
for i:= 0 ;i<l;i++{
ch := s1[i] // 依據(jù)下標(biāo)取字符串中的字符,類(lèi)型為byte
fmt.Printf("%T,%d,%d\n",ch,i,ch)
}
}
uint8,0,103
uint8,1,111
uint8,2,108
uint8,3,97
uint8,4,110
uint8,5,103
uint8,6,32
uint8,7,228
uint8,8,184
uint8,9,173
uint8,10,229
uint8,11,155
uint8,12,189
以u(píng)nicode字符遍歷數(shù)組
package main
import "fmt"
func main(){
var s1 string = "golang 中國(guó)"
for i,v := range s1{
// v是rune類(lèi)型
fmt.Printf("%d,%T,%d,%c\n",i,v,v,v)
}
}
0,int32,103,g
1,int32,111,o
2,int32,108,l
3,int32,97,a
4,int32,110,n
5,int32,103,g
6,int32,32,
7,int32,20013,中
10,int32,22269,國(guó)
6.1 補(bǔ)充1:基本數(shù)據(jù)類(lèi)型轉(zhuǎn)換
Go語(yǔ)言中不同類(lèi)型變量之間相互賦值時(shí)需要顯式轉(zhuǎn)換(不能自動(dòng)轉(zhuǎn)換)
轉(zhuǎn)換的表達(dá)式 T(v) , 意思是將v轉(zhuǎn)換成T類(lèi)型
多見(jiàn)于整數(shù)的不同類(lèi)型之間的轉(zhuǎn)換,或者不同浮點(diǎn)數(shù)類(lèi)型之間的轉(zhuǎn)換,或是整數(shù)與浮點(diǎn)數(shù)之間的相互轉(zhuǎn)
package main
import "fmt"
func main() {
var v1 int8 = 99
var v2 int
fmt.Printf("v1 type is %T,value is %d\n",v1,v1)
fmt.Printf("v2 type is %T,value is %d\n",v2,v2)
v2 = int(v1)
fmt.Printf("v2 type is %T,value is %d\n",v2,v2)
}
v1 type is int8,value is 99
v2 type is int,value is 0
v2 type is int,value is 99
GO語(yǔ)言中數(shù)據(jù)類(lèi)型的值范圍可以從大向小轉(zhuǎn)換,也可以從小向大轉(zhuǎn)換
package main
import "fmt"
func main() {
// int8 的范圍是 -128 ~ 127
var v1 int8
var v2 int64 = 9999999
var v3 float64
// 不會(huì)報(bào)錯(cuò), 結(jié)果是按溢出處理
v1 = int8(v2)
v3 = float64(v2)
fmt.Printf("%T, %d\n",v1,v1)
fmt.Printf("%T, %f\n",v3,v3)
}
int8, 127
float64, 9999999.000000
6.2 補(bǔ)充2 基本數(shù)據(jù)類(lèi)型和string 類(lèi)型的轉(zhuǎn)換
在實(shí)際應(yīng)用中,string 類(lèi)型和基礎(chǔ)類(lèi)型的相互轉(zhuǎn)換非常常見(jiàn)
例如,整數(shù)類(lèi)和浮點(diǎn)數(shù)類(lèi)型,bool型等與string類(lèi)型之間的轉(zhuǎn)換
基礎(chǔ)類(lèi)型轉(zhuǎn)成string類(lèi)型
方法1: 通過(guò)包 fmt 包的Sprintf()函數(shù)去實(shí)現(xiàn)
package main
import "fmt"
func main(){
var v1 int64 = 99998767
var f float64 = 90.7978
var b bool = true
var ch byte = 'w'
var s string
s = fmt.Sprintf("%d",v1)
fmt.Printf("v2 = %s, %T\n",s,s)
s = fmt.Sprintf("%f",f)
fmt.Printf("v2 = %s, %T\n",s,s)
s = fmt.Sprintf("%t",b)
fmt.Printf("v2 = %s, %T\n",s,s)
s = fmt.Sprintf("%c",ch)
fmt.Printf("v2 = %s, %T\n",s,s)
}
v2 = 99998767, string
v2 = 90.797800, string
v2 = true, string
v2 = w, string
基礎(chǔ)數(shù)據(jù)類(lèi)型轉(zhuǎn)換成string類(lèi)型
方法2 : 使用 strconv 包中的函數(shù)實(shí)現(xiàn)
package main
import (
"fmt"
"strconv"
)
func main() {
var n int8 = 12
var f float64 = 23.001
var b bool = false
// FormatInt函數(shù)中傳入的第一個(gè)參數(shù)應(yīng)該是int64類(lèi)型
s := strconv.FormatInt(int64(n),10)
fmt.Printf("s = %s and type = %T\n",s,s)
// 其中的參數(shù)說(shuō)明參考文檔
s = strconv.FormatFloat(f,'f',10,64)
fmt.Printf("s = %s and type = %T\n",s,s)
s = strconv.FormatBool(b)
fmt.Printf("s = %s and type = %T\n",s,s)
}
s = 12 and type = string
s = 23.0010000000 and type = string
s = false and type = string
strconv 包中有其他的方法可以將string類(lèi)型轉(zhuǎn)換成整數(shù)類(lèi)型,浮點(diǎn)數(shù)類(lèi)型,bool類(lèi)型,函數(shù)名為 ParseInt() ParseBool() ParseFloat() **ParseUint()
package main
import (
"fmt"
"strconv"
)
func main() {
var s1 string = "99090"
var s2 string = "12.090"
var s3 string = "true"
var s4 string = "97"
var s5 string = "helloworld"
n, _ := strconv.ParseInt(s1, 10, 64)
fmt.Printf("n = %d,type = %T\n", n, n)
f, _ := strconv.ParseFloat(s2, 64)
fmt.Printf("f = %f,type = %T\n", f, f)
b, _ := strconv.ParseBool(s3)
fmt.Printf("b = %t,type = %T\n", b, b)
n2, _ := strconv.ParseUint(s4, 10, 64)
fmt.Printf("n2 = %d,type = %T\n", n2, n2)
// 錯(cuò)誤原因是s5的有效數(shù)據(jù)不能轉(zhuǎn)換成指定的類(lèi)型
n3, err := strconv.ParseInt(s5, 10, 64)
if err !=nil{
fmt.Println("error = ",err)
}else{
fmt.Printf("n = %d,type = %T\n", n3, n3)
}
}
n = 99090,type = int64
f = 12.090000,type = float64
b = true,type = bool
n2 = 97,type = uint64
error = strconv.ParseInt: parsing "helloworld": invalid syntax
7. 補(bǔ)充3 Go語(yǔ)言中常見(jiàn)轉(zhuǎn)義符
轉(zhuǎn)義符 | 含義 |
---|---|
\r | 回車(chē)符(返回行首) |
\n | 換行符 |
\t | 制表符 |
\' | 單引號(hào) |
\" | 雙引號(hào) |
\\ | 反斜杠 |
package main
import "fmt"
func main() {
var s1 string = "\"D:\\Go\\bin\\go.exe\""
fmt.Println(s1)
}
"D:\Go\bin\go.exe"