Go語言將數據類型分為四類:基礎類型、復合類型、引用類型和接口類型。
基礎數據類型包括:
- 基礎類型:
- 布爾型、整型、浮點型、復數型、字符型、字符串型、錯誤類型。 - 復合數據類型包括:
- 指針、數組、切片、字典、通道、結構體、接口。
基礎數據類型
布爾值和布爾表達式
布爾類型的變量取值結果要么是真,要么是假,用bool關鍵字進行定義
布爾類型默認值為 false
指定格式的輸出 %t
| 語法 | 描述/結果 |
|---|---|
| !b | 邏輯非操作符 b值為true 則 操作結果為false |
| a || b | 短路邏輯或,只要布爾值 a b 中任何一個為true表達式結果都為true |
| a && b | 短路邏輯與,兩個表達式a b都為true,則整個表達式結果為true |
| x > y | 表達式x的值小於表達式Y的值,則表達式的結果為true |
數值類型
go語言提供了大內置的數值類型,標准庫也提供了big.Int類型的整數,和big.Rat類型的有理數,這些都是大小不限(只限於機器內存)
整型
GO語言提供了11種整型,包含5種有符號,和5種無符號的與一種用於存儲指針的整數類型。Go語言允許使用byte來作為無符號uint8類型的同義詞,在使用單個字符時提倡使用rune來替代 int32
| 類型 | 存儲空間 | 取值范圍 |
|---|---|---|
| byte | 8-bit | 同uint8 |
| int | 系統決定 | 依賴不通平台實現,32位操作系統為int32的值范圍,64位操作系統為int64的值范圍 |
| int8 | 8-bit | [-128, 127] ,表示 UTF-8 字符串的單個字節的值,對應 ASCII 碼的字符值 |
| int16 | 16-bit | [-32678, 32767] |
| int32 | 32-bit | [2147483648, 2147483647] |
| int64 | 64-bit | [-9223372036854775808 , 9223372036854775807] |
| rune | 32-bit | 同uint32,表示 單個 Unicode 字符 |
| uint | 系統決定 | 依賴不通平台下的實現,可以是uint32或uint64 |
| uint8 | 8-bit | |
| uint16 | 16-bit | [0, 65535] |
| uint32 | 32-bit | [0, 4294967295] |
| uint64 | 64-bit | [0, 18446744073709551615] |
| uintptr | 系統決定 | 一個可以恰好容納指針值得無符號整數類型(32位操作系統為uint32的值范圍,64位系統為uint64的值范圍) |
浮點類型
Go語言提供了兩種類型的浮點類型和兩種類型的復數類型,
| 類型 | 存儲空間 | 取值范圍 |
|---|---|---|
| float32 | 32-bit | [1.401298464324817070923729583289916131280e-45 , 3.402823466385288598117041834516925440e+38] 精確到小數點后7位 |
| float64 | 64-bit | [4.940656458412465441765687928682213723651e-324 , 1.797693134862315708145274237317043567981e+308] 精確到小數點后15位 |
| complexm64 | 64-bit | 實部和虛部都是一個float32 |
| complexm128 | 128-bit | 實部和虛部都是一個float64 |
fmt.printf("%.2f",num) // 保留兩位小數,同時進行了四舍五入
字符串 (string)
字符串使用雙引號 " 或者反引號 ```來創建,雙引號可以解析字符串變量
定義字符變量用 byte 關鍵詞 var ch byte = 'a' 8-bit,代表了 ASCII 碼的一個字符。指定格式的輸出 %c
定義字符變量用 rune 關鍵詞 var ch rune = 'a' 32-bit 代表了 Unicode(UTF-8)碼的一個字符。
定義字符變量用 string 關鍵詞 var ch string = "abc"指定格式的輸出 %s
字符串的結束標志 \0,Go語言使用的UTF8編碼,英文占1個字符,一個漢字占3個字符
自動推導類型
自動推到類型,創建的浮點型默認為 float64,整型為int
a := "123"
a := 10
使用fmt格式化輸出
格式指令通常由用於輸出單個值,每個值都按格式指令格式化。用於fmt.Printf() fmt.Errorf() fmt.Fprintf() fmt.Sprintf()函數的格式字符串包含一個或多個格式指令
| 格式指令 | 含義/結果 |
|---|---|
| %b | 二進制數值 |
| %c | 數值對應的 Unicode 編碼字符 |
| %d | 十進制數值 |
| %o | 八制數值 |
| %e | 科學計數法,e表示 |
| %E | 科學計數法,E表示 |
| %f | 有小數部分,無指數部分 |
| %g | 以%f或%e表示浮點數或復數 |
| %G | 以%f或%E表示浮點數或復數 |
| %s | 直接輸出字符串或者[]byte |
| %q | 雙引號括起來的字符串或者[]byte |
| %x | 每個字節用兩字節十六進制表示,a-f表示 |
| %X | 每個字節用兩字節十六進制表示,A-F表示 |
| %t | 以true或fales輸出布爾值 |
| %T | 輸出值得類型 |
| %v | 默認格式輸出內置或自定義類型的值 |
強制類型轉換
類型轉換用於將一種數據類型轉換為另外一種類型
var num float64 = 3.15
fmt.Printf("%d", int(num))
類型不一致的不能進行運算,在類型轉換時,建議將低類型轉換為高類型,保證數據精度,高類型轉換成地類型,可能會丟失精度,或數據溢出
復合數據類型
數組
數組,一系列同一類型數據的集合,數組是值類型,在初始化后長度是固定的,無法修改其長度。
數組的定義
var arr [元素數量]類型
數組初始化
全部初始化 var arr [5]int = [5]int{1,2,3,4,5}
部分初始化 var arr [5]int = [5]int{1,2} ,沒有指定初值的元素將會賦值為其元素類型(int)的默認值(0)
指定下標初始化 var arr = [5]int{2:5, 3:6} key:value的格式
通過初始化確定數組長度,var arr = [...]int{1, 2, 3} 長度是根據初始化時指定個數
相同空間大小(類型)的數組可以用 == != 來比較是否相同。
package main
import "fmt"
func main() {
var arr [2]int = [2]int{1, 2}
var arr2 [2]int = [...]int{2, 2}
fmt.Println(arr == arr2)
}
D:\go_work\src>go run main.go
false
數組的遍歷
- 通過
for .. len()完成遍歷 - 通過
for .. range完成遍歷
作為函數值傳遞
golang數組是值類型,當數組作為函數參數,函數中修改數組中的值,不會影響原數組
package main
import "fmt"
func test(t [2]int) {
fmt.Println(&t)
}
func main() {
var arr [2]int = [2]int{1, 2}
test(arr)
}
二維數組
初始化方式
- 全部初始化
var arr [2][2]int = [2][2]int{ {1,2},{3,4} } - 部分初始化
var arr [2][2]int = [2][2]int{ {1,2},{3} } - 指定元素初始化
var arr [2][2]int = [2][2]int{ 1:{1} },var arr [2][2]int = [2][2]int{ 1:{1:3} } - 通過初始化確定二維數組行數
var arr [...][2]int = [2][2]int{ {1,2},{3,4} }行下標可以用...列下標不可用...
map
Go語言中的字典結構是有鍵和值構成的,所謂的鍵,就類似於字典的索引,可以快速查詢出對應的數據。
map是只用無序的鍵值對的集合。
map最重要的一點是通過key來快速檢索數據,key類似於索引,指向數據的值。
map中key的值是不能重復的
引用類型或包含引用類型的數據類型不能作為key
map的創建
- 字面量:
var map_name map[keyType]valType - 類型推導:
map_name := map[keyType]valType - 關鍵詞:
make(map[keyType]valType)
map的初始化
- 字面量:
var maps[int]string = map[int]string{1: "zhangsan", 2: "lisi"} - 類型推導:
maps := map[int]string{1: "zhangsan", 2: "lisi"} - 關鍵詞:
maps := make(map[string]int,10);maps["zhangsan"] = 14
map的key value
通過key獲取值時,判斷key是否存在 var1, var2 := map[key],如存在,var1存儲對應的值,var2的值為true,var2否則為false
package main
import "fmt"
func initial(t []int) {
for n := 0; n < 10; n++ {
t[n] = n
}
}
func main() {
var m map[int]string = map[int]string{1: "zhangsan", 2: "lisi"}
fmt.Println(m)
v, ok := m[2]
if ok {
fmt.Println(v)
} else {
fmt.Println(ok)
}
v, ok = m[3]
if ok {
fmt.Println(v)
} else {
fmt.Println(ok)
}
}

delete(map,2) 通過key刪除某個值
作為函數參數傳遞
slice map channel都是引用類型,所以改變是改變的變量的地址。
package main
import "fmt"
func initial(t map[int]string) {
for n := 0; n < 10; n++ {
t[n] = fmt.Sprintf("aaa%d", n)
}
}
func main() {
var m = make(map[int]string, 10)
initial(m)
fmt.Println(m)
}

切片
切片與數組相比,切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大,所以可以將切片理解為“動態數組”,但是,它不是數組。
切片定義
var slice_name []type 默認空切片,長度為0
slice_name := []type{} 默認空切片,長度為0
make([]type, length, capacity) length:已初始化的空間,capacity:已開辟的空間(length+空閑)。length不能大於capacity
len() 返回長度 cap() 返回容量
如果使用字面量的方式創建切片,大部分的工作就都會在編譯期間完成,使用 make() 關鍵字創建切片時,很多工作都需要運行時的參與。
切片初始化
通過 var slice_name []type 方式創建
import "fmt"
func main() {
var slices []int
slices = append(slices, 1, 2, 3, 4, 5, 6)
fmt.Print(slices)
slices = append(slices, 100, 99)
fmt.Print(slices)
}

通過 slice_name := []type{} 方式創建
- 直接在
{}中添加值 - 通過
append()添加
通過 make([]type, length, capacity) 方式創建
package main
import "fmt"
func main() {
var slices []int
slices = make([]int, 3, 5)
slices[0] = 1
slices[1] = 2
slices[2] = 3
slices[3] = 4
fmt.Println(slices)
}

切片的截取
切片截取
| 操作 | 含義 |
|---|---|
| s[n] | 切片s中索引位置為N的項 |
| s[:] | 從切片s的索引位置到 len(s) - 1 處所獲得的切片 |
| s[low:] | 從切片s的索引位置low到 len(s) - 1 處所獲得的切片 |
| s[:high] | 從切片s的索引位置0到high處所獲得的切片 len=high |
| s[low:higt] | 從切片s的索引位置low到high處所獲得的切片 len=high-low |
| s[low:higt:max] | 從切片s的索引位置low到high處所獲得的切片,len=high-low,cap=max-low |
| len(s) | 切片s的長度,<=cap(s) |
| cap(s) | 切片s的容量,>=len(s) |
slice[startVal, length, Capacity]
容量為:capacity - startVal
長度為: length - startVal
package main
import "fmt"
func main() {
var slices []int
slices = []int{1, 2, 3, 4, 5, 6, 7, 8}
s := slices[1:3:5]
fmt.Println(s)
fmt.Println(len(s))
fmt.Println(cap(s))
}

在截取時,capacity 不能超過原slice的 capacity
package main
import "fmt"
func main() {
var slices []int
slices = []int{1, 2, 3, 4, 5, 6, 7, 8}
s := slices[1:3:10]
fmt.Println(s)
fmt.Println(len(s))
fmt.Println(cap(s))
}

切片值得修改
問:切片截取后返回新切片,對新切片的值修改,會影響原切片嗎
當對切片進行截取操作后,產生了新的切片,新的切片是指向原有切片的,對新切片值修改,會影響到原有切片
package main
import "fmt"
func main() {
var slices []int
slices = []int{1, 2, 3, 4, 5, 6, 7, 8}
s := slices[1:3]
s[1] = 100
fmt.Println(s)
fmt.Println(slices)
}

追加和拷貝
append(slice, 1,2,3)向切片末尾追加數據copy(slice1, slice2)拷貝的長度為兩個切片中長度較小的長度值
作為參數值傳遞,切片是數組的一個引用,因此切片是引用類型,操作會修改原有切片
package main
import "fmt"
func initial(t []int) {
for n := 0; n < 10; n++ {
t[n] = n
}
}
func main() {
var slices = make([]int, 10)
fmt.Println(slices)
initial(slices)
fmt.Println(slices)
}

切片擴容
切片擴容,一般方式:上一次容量的2倍,超過1024字節,每次擴容上一次的1/4
package main
import "fmt"
func initial(t []int) {
for n := 0; n < 10; n++ {
t[n] = n
}
}
func main() {
var slices = make([]int, 3)
var slices1 = []int{4, 5}
copy(slices, slices1)
fmt.Println(slices)
fmt.Println(slices1)
}

struct 結構體
結構體 struct 是由一系列具有相同類型或不同類型的數據構成的數據集合,結構體可以很好的管理一批有聯系的數據,使用結構體可以提高程序的易讀性。Go中提供了對 struct 的支持,與數組一樣,struct屬於復合類型,並非引用類型。
Go語言中結構體包含以下特性
- 值傳遞,Go語言中結構體和數組一樣是值類型,可以聲明結構體指針向下傳遞
- 不可繼承,Go語言中沒有繼承的概念,在結構體中,可以通過組合結構體,來構建更復雜的結構體。
- 結構體不能包含自己。
結構體聲明
成員名稱前不能加 var
type Student struct {
id int
name string
age int
addr string
}
空結構體
結構體也可以不包含任何字段,稱為空結構體 struct{}
結構體初始化
- 順序初始化
var stu = Student{ id:101, name:"zhangsan", age:19, addr:"shanghai" } - 指定成員初始化
var stu = Student{name:"zhangsan", age:19} - 通過
結構體變量.成員完成初始化var stu Student stu.age=19 stu.addr="peking"
結構體傳遞
結構體與數組一樣,都是值傳遞,將結構體作為函數實參傳給函數的形參時,會復制一個副本,所以為了提高性能,在結構體傳給函數時,可以使用指針結構體。
指針結構體定義:聲明結構體變量時,在結構體類型前加 * 號,便聲明一個指向結構體的指針。 var stu *Student。
指針結構體訪問: 由於.的優先級高於*struct_name,故在使用時,需要對結構體加括號。(*struct_name).成員屬性 (*stu).name
