基礎
安裝Go擴展
go build
在項目目錄下執行go build
go run
像執行腳本文件一樣執行Go代碼
go install
go install
分為兩步:
1、?先編譯得到一個可執行文件
2、將可執行文件拷貝到GOPATH/bin
Go 命令
go build
:編譯Go程序
go build -o "xx.exe"
:編譯成xx.exe文件
go run main.go
: 像執行腳本一樣執行main.go文件
go install
: 先編譯后拷貝
變量
3種聲明方式:
-
var name1 string
-
var name2 = "沙河娜扎"
-
函數內部專屬:
name3:="沙河小王子"
常量
const PI = 3.1415926
const UserNotExistErr = 10000
iota:實現枚舉
兩個要點:
-
iota
在const關鍵字出現時將被重置為0 -
const中每新增一行常量聲明,iota累加1
基本數據類型
整型
無符號整型:uint8
、uint16
、uint32
、uint64
帶符號整型:int8
、int16
、int32
、int64
uint
和int
:具體是32位還是64位看操作系統
uintptr
:表示指針
浮點型
float64
和float32
Go語言中浮點數默認是float64
復數
complex128
和complex64
布爾值
true
和false
不能和其他的類型做轉換
字符串
常用方法
字符串不能修改
byte和rune類型
都屬于類型別名
復合數據類型
????????數組
數組的聲明
// 數組是存放元素的容器
// 必須指定存放的元素的類型和容量(長度)
// 數組的長度是數組類型的一部分
var a1 [3]bool // [true false true]
var a2 [4]bool // [true true false false]
fmt.Printf("a1:%T a2:%T\n", a1, a2)
數組的初始化
// 數組的初始化
// 如果不初始化:默認元素都是零值(布爾值:false, 整型和浮點型都是0, 字符串:"")
fmt.Println(a1, a2)
// 1. 初始化方式1
a1 = [3]bool{true, true, true}
fmt.Println(a1)
// 2. 初始化方式2:根據初始值自動推斷數組的長度是多少
// a10 := [9]int{0, 1, 2, 3, 4, 4, 5, 6, 7}
a10 := [...]int{0, 1, 2, 3, 4, 4, 5, 6, 7}
fmt.Println(a10)
// 3. 初始化方式3:根據索引來初始化
a3 := [5]int{0: 1, 4: 2}
fmt.Println(a3)
數組的遍歷
// 數組的遍歷
citys := [...]string{"北京", "上海", "深圳"} // 索引:0~2 citys[0],citys[1],citys[2]
// 1. 根據索引遍歷
for i := 0; i < len(citys); i++ {
?? ?fmt.Println(citys[i])
}
// 2. for range遍歷
for i, v := range citys {
?? ?fmt.Println(i, v)
}
二維數組
// 多維數組
// [[1 2] [3 4] [5 6]]
var a11 [3][2]int
a11 = [3][2]int{
?? ?[2]int{1, 2},
?? ?[2]int{3, 4},
?? ?[2]int{5, 6},
}
fmt.Println(a11)
// 多維數組的遍歷
for _, v1 := range a11 {
?? ?fmt.Println(v1)
?? ?for _, v2 := range v1 {
?? ??? ?fmt.Println(v2)
?? ?}
}
數組是值類型
// 數組是值類型
b1 := [3]int{1, 2, 3} // [1 2 3]
b2 := b1 ? ? ? ? ? ? ?// [1 2 3] Ctrl+C Ctrl+V => 把world文檔從文件夾A拷貝到文件夾B
b2[0] = 100 ? ? ? ? ? // b2:[100 2 3]
fmt.Println(b1, b2) ? // b1:[1 2?
切片(slice)
切片指向了一個底層的數組。
切片的長度就是它元素的個數。
切片的容量是底層數組從切片的第一個元素到最后一個元素的數量。
切片的定義
// 切片的定義
var s1 []int ? ?// 定義一個存放int類型元素的切片
var s2 []string // 定義一個存放string類型元素的切片
fmt.Println(s1, s2)
fmt.Println(s1 == nil) // true
fmt.Println(s2 == nil) // true
切片的初始化
// 初始化
s1 = []int{1, 2, 3}
s2 = []string{"沙河", "張江", "平山村"}
fmt.Println(s1, s2)
fmt.Println(s1 == nil) // false
fmt.Println(s2 == nil) // false
切片的長度和容量
// 長度和容量
fmt.Printf("len(s1):%d cap(s1):%d\n", len(s1), cap(s1))
fmt.Printf("len(s2):%d cap(s2):%d\n", len(s2), cap(s2)
make
make()函數用于創建指定長度和容量的切片。
s1 := make([]int, 5, 10)
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
s2 := make([]int, 0, 10)
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s2, len(s2), cap(s2))
切片的本質
切片就是一個框,框住了一塊連續的內存。
切片屬于引用類型,真正的數據都是保存在底層數組里的。
判斷一個切片是否是空的,要是用len(s) == 0
來判斷
append
// 調用append函數必須用原來的切片變量接收返回值
// append追加元素,原來的底層數組放不下的時候,Go底層就會把底層數組換一個
// 必須用變量接收append的返回值
s1 = append(s1, "廣州")
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
s1 = append(s1, "杭州", "成都")
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
ss := []string{"武漢", "西安", "蘇州"}
s1 = append(s1, ss...) // ...表示拆開
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
copy
a1 := []int{1, 3, 5}
a2 := a1 // 賦值
var a3 = make([]int, 3, 3)
copy(a3, a1) // copy
fmt.Println(a1, a2, a3)
a1[0] = 100
fmt.Println(a1, a2, a3)
指針
Go語言中不存在指針操作,只需要記住兩個符號:
-
&
:取地址 -
*
:根據地址取值
make和new的區別
-
make和new都是用來申請內存的
-
new很少用,一般用來給基本數據類型申請內存,
string
、int
,返回的是對應類型的指針(*string、*int)。 -
make是用來給
slice
、map
、chan
申請內存的,make函數返回的的是對應的這三個類型本身
map
map也是引用類型,必須初始化之后才能使用。
func main() {
?? ?var m1 map[string]int
?? ?fmt.Println(m1 == nil) ? ? ? ?// 還沒有初始化(沒有在內存中開辟空間)
?? ?m1 = make(map[string]int, 10) // 要估算好該map容量,避免在程序運行期間再動態擴容
?? ?m1["理想"] = 18
?? ?m1["jiwuming"] = 35
?? ?fmt.Println(m1)
?? ?fmt.Println(m1["理想"])
?? ?// 約定成俗用ok接收返回的布爾值
?? ?fmt.Println(m1["娜扎"]) // 如果不存在這個key拿到對應值類型的零值
?? ?value, ok := m1["娜扎"]
?? ?if !ok {
?? ??? ?fmt.Println("查無此key")
?? ?} else {
?? ??? ?fmt.Println(value)
?? ?}
?? ?// map的遍歷
?? ?for k, v := range m1 {
?? ??? ?fmt.Println(k, v)
?? ?}
?? ?// 只遍歷key
?? ?for k := range m1 {
?? ??? ?fmt.Println(k)
?? ?}
?? ?// 只遍歷value
?? ?for _, v := range m1 {
?? ??? ?fmt.Println(v)
?? ?}
?? ?// 刪除
?? ?delete(m1, "jiwuming")
?? ?fmt.Println(m1)
?? ?delete(m1, "沙河") // 刪除不存在的key
}
函數
// 函數
// 函數存在的意義?
// 函數是一段代碼的封裝
// 把一段邏輯抽象出來封裝到一個函數中,給它起個名字,每次用到它的時候直接用函數名調用就可以了
// 使用函數能夠讓代碼結構更清晰、更簡潔。
// 函數的定義
func sum(x int, y int) (ret int) {
?? ?return x + y
}
// 沒有返回值
func f1(x int, y int) {
?? ?fmt.Println(x + y)
}
// 沒有參數沒有返回值
func f2() {
?? ?fmt.Println("f2")
}
// 沒有參數但有返回值的
func f3() int {
?? ?ret := 3
?? ?return ret
}
// 返回值可以命名也可以不命名
// 命名的返回值就相當于在函數中聲明一個變量
func f4(x int, y int) (ret int) {
?? ?ret = x + y
?? ?return // 使用命名返回值可以return后省略
}
// 多個返回值
func f5() (int, string) {
?? ?return 1, "沙河"
}
// 參數的類型簡寫:
// 當參數中連續多個參數的類型一致時,我們可以將非最后一個參數的類型省略
func f6(x, y, z int, m, n string, i, j bool) int {
?? ?return x + y
}
// 可變長參數
// 可變長參數必須放在函數參數的最后
func f7(x string, y ...int) {
?? ?fmt.Println(x)
?? ?fmt.Println(y) // y的類型是切片 []int
}
// Go語言中函數沒有默認參數這個概念
func main() {
?? ?r := sum(1, 2)
?? ?fmt.Println(r)
?? ?_, n := f5()
?? ?fmt.Println(n)
?? ?f7("下雨了")
?? ?f7("下雨了", 1, 2, 3, 4, 5, 6, 7)
}