1. 程式人生 > 實用技巧 >go學習筆記1

go學習筆記1

hello GO

這裡使用vscode

  1. 安裝外掛go

  2. 新建hello資料夾,建立main.go檔案

    package main
    import "fmt"
    func main(){
    	fmt.Println("Hello")
    }
    
    1. 開啟命令列

  3. 執行go build 這時同目錄會建立一個hello.exe的檔案(我這裡使用的是win電腦)

    也可以使用 go build -o aaa.exe 指定檔名

也直接輸出可使用 go run main.go

跨平臺編譯

只需要指定目標作業系統的平臺和處理器架構即可:

SET CGO_ENABLED=0  // 禁用CGO
SET GOOS=linux  // 目標平臺是linux
SET GOARCH=amd64  // 目標處理器架構是amd64

然後再執行go build命令,得到的就是能夠在Linux平臺執行的可執行檔案了。

Mac 下編譯 Linux 和 Windows平臺 64位 可執行程式:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

Linux 下編譯 Mac 和 Windows 平臺64位可執行程式:

CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build

Windows下編譯Mac平臺64位可執行程式:

SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build

基礎

//單行註釋

/*

多行註釋

*/

fmt.Println('列印輸出')

一行程式碼不需加分號

變數聲明後必須使用,不使用會報錯

縮排沒有嚴格要求

變數和常量

標書與關鍵字

Go語言中識別符號由字母數字和_(下劃線)組成,並且只能以字母和_開頭。

關鍵詞

25個關鍵詞

   break        default      func         interface    select
    case         defer        go           map          struct
    chan         else         goto         package      switch
    const        fallthrough  if           range        type
    continue     for          import       return       var

37個保留詞

    Constants:    true  false  iota  nil

       	Types:    int  int8  int16  int32  int64  
                  uint  uint8  uint16  uint32  uint64  uintptr
                  float32  float64  complex128  complex64
                  bool  byte  rune  string  error

    Functions:   make  len  cap  new  append  copy  close  delete
                 complex  real  imag
                 panic  recover

變數

宣告: var 變數名 變數型別

單個宣告
var aaa string
var age int
var iss bool

批量宣告
var (
	a string
	b int
	c bool
)

變數初始化: var 變數名 型別 = 表示式

var name string = "aa"

一次初始化多個變數
var name,age = "bb",20

短變數宣告(宣告並初始化) :=

n:=10
m:=50

匿名變數:用一個下劃線_表示

匿名變數不佔用名稱空間,不會分配記憶體,所以匿名變數之間不存在重複宣告。 (在Lua等程式語言裡,匿名變數也被叫做啞元變數。)

func foo() (int, string) {
	return 10, "Q1mi"
}
func main() {
	x, _ := foo()
	_, y := foo()
	fmt.Println("x=", x)
	fmt.Println("y=", y)
}

注意:

函式外的每個語句都必須以關鍵字開始(var、const、func等)

:=不能使用在函式外。

_多用於佔位,表示忽略值。

常量const

const a = 'dsadasd'

和變數類似

const (
	a string
	b int
	c bool
)

iota : go語言的常量計數器

iota在const關鍵字出現時將被重置為0

const (
		n1 = iota //0
		n2        //1
		n3        //2
		n4        //3
	)

使用_調過某些值
const (
		n1 = iota //0
		n2        //1
		_
		n4        //3
	)	

iota宣告中間插隊

const (
		n1 = iota //0
		n2 = 100  //100
		n3 = iota //2
		n4        //3
	)
	const n5 = iota //0

多個iota定義在一行

const (
		a, b = iota + 1, iota + 2 //1,2
		c, d                      //2,3
		e, f                      //3,4
	)

資料型別

整型

Go語言中有豐富的資料型別,除了基本的整型、浮點型、布林型、字串外,還有陣列、切片、結構體、函式、map、通道(channel)等。

型別 描述
uint8 無符號 8位整型 (0 到 255)
uint16 無符號 16位整型 (0 到 65535)
uint32 無符號 32位整型 (0 到 4294967295)
uint64 無符號 64位整型 (0 到 18446744073709551615)
int8 有符號 8位整型 (-128 到 127)
int16 有符號 16位整型 (-32768 到 32767)
int32 有符號 32位整型 (-2147483648 到 2147483647)
int64 有符號 64位整型 (-9223372036854775808 到 9223372036854775807)

特殊整型

型別 描述
uint 32位作業系統上就是uint32,64位作業系統上就是uint64
int 32位作業系統上就是int32,64位作業系統上就是int64
uintptr 無符號整型,用於存放一個指標

進位制

	// 十進位制
	var a int = 10
	fmt.Printf("%d \n", a)  // 10
	fmt.Printf("%b \n", a)  // 1010  佔位符%b表示二進位制
 
	// 八進位制  以0開頭
	var b int = 077
	fmt.Printf("%o \n", b)  // 77
 
	// 十六進位制  以0x開頭
	var c int = 0xff
	fmt.Printf("%x \n", c)  // ff
	fmt.Printf("%X \n", c)  // FF

浮點型

Go語言支援兩種浮點型數:float32float64

package main
import (
        "fmt"
        "math"
)
func main() {
        fmt.Printf("%f\n", math.Pi)
        fmt.Printf("%.2f\n", math.Pi)
}

複數

complex64和complex128

複數有實部和虛部,complex64的實部和虛部為32位,complex128的實部和虛部為64位。

var c1 complex64
c1 = 1 + 2i
var c2 complex128
c2 = 2 + 3i
fmt.Println(c1)
fmt.Println(c2)

布林值

Go語言中以bool型別進行宣告布林型資料,布林型資料只有true(真)false(假)兩個值。

注意:

  1. 布林型別變數的預設值為false
  2. Go 語言中不允許將整型強制轉換為布林型.
  3. 布林型無法參與數值運算,也無法與其他型別進行轉換。

字串

s1 := "hello"
s2 := "你好"

字串轉義符

轉義符 含義
\r 回車符(返回行首)
\n 換行符(直接跳到下一行的同列位置)
\t 製表符
\' 單引號
\" 雙引號
\\ 反斜槓

多行字串 使用反引號

字串的常用操作

方法 介紹
len(str) 求長度
+或fmt.Sprintf 拼接字串
strings.Split 分割
strings.contains 判斷是否包含
strings.HasPrefix,strings.HasSuffix 字首/字尾判斷
strings.Index(),strings.LastIndex() 子串出現的位置
strings.Join(a[]string, sep string) join操作

byte和rune型別

字元用單引號(’)包裹起來

  1. nt8型別,或者叫 byte 型,代表了ASCII碼的一個字元。
  2. rune型別,代表一個 UTF-8字元

當需要處理中文、日文或者其他複合字符時,則需要用到rune型別。rune型別實際是一個int32

修改字串

要修改字串,需要先將其轉換成[]rune[]byte,完成後再轉換為string。無論哪種轉換,都會重新分配記憶體,並複製位元組陣列。

func changeString() {
	s1 := "big"
	// 強制型別轉換
	byteS1 := []byte(s1)
	byteS1[0] = 'p'
	fmt.Println(string(byteS1))

	s2 := "白蘿蔔"
	runeS2 := []rune(s2)
	runeS2[0] = '紅'
	fmt.Println(string(runeS2))
}

型別轉換

強制轉換

T(表示式)
T表示要轉換的型別。表示式包括變數、複雜運算元和函式返回值等.

運算子

  1. 算術運算子 + - * / %

  2. 關係運算符 == != > >= < <=

  3. 邏輯運算子 && || !

  4. 位運算子

    運算子 描述
    & 參與運算的兩數各對應的二進位相與。 (兩位均為1才為1)
    | 參與運算的兩數各對應的二進位相或。 (兩位有一個為1就為1)
    ^ 參與運算的兩數各對應的二進位相異或,當兩對應的二進位相異時,結果為1。 (兩位不一樣則為1)
    << 左移n位就是乘以2的n次方。 “a<<b”是把a的各二進位全部左移b位,高位丟棄,低位補0。
    >> 右移n位就是除以2的n次方。 “a>>b”是把a的各二進位全部右移b位。
  5. 賦值運算子 = += -= *= /= %= <<= >>= &= |= ^=

流程控制

ifelse

if 表示式1 {
    分支1
} else if 表示式2 {
    分支2
} else{
    分支3
}

for

for 初始語句;條件表示式;結束語句{
    迴圈體語句
}
完整
func forDemo() {
	for i := 0; i < 10; i++ {
		fmt.Println(i)
	}
}
初始語句省略
func forDemo2() {
	i := 0
	for ; i < 10; i++ {
		fmt.Println(i)
	}
}
初始語句/結束語句結束
func forDemo3() {
	i := 0
	for i < 10 {
		fmt.Println(i)
		i++
	}
}
無限迴圈
for {
    迴圈體語句
}

for range(鍵值迴圈)

switch case

func switchDemo1() {
	finger := 3
	switch finger {
	case 1:
		fmt.Println("大拇指")
	case 2:
		fmt.Println("食指")
	case 3:
		fmt.Println("中指")
	case 4:
		fmt.Println("無名指")
	case 5:
		fmt.Println("小拇指")
	default:
		fmt.Println("無效的輸入!")
	}
}
func testSwitch3() {
	switch n := 7; n {
	case 1, 3, 5, 7, 9:
		fmt.Println("奇數")
	case 2, 4, 6, 8:
		fmt.Println("偶數")
	default:
		fmt.Println(n)
	}
}

fallthrough語法可以執行滿足條件的case的下一個case,是為了相容C語言中的case設計的。

func switchDemo5() {
	s := "a"
	switch {
	case s == "a":
		fmt.Println("a")
		fallthrough
	case s == "b":
		fmt.Println("b")
	case s == "c":
		fmt.Println("c")
	default:
		fmt.Println("...")
	}
}
輸出:
a
b

goto

通過標籤進行程式碼間的無條件跳轉

func gotoDemo2() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// 設定退出標籤
				goto breakTag
			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
	return
	// 標籤
breakTag:
	fmt.Println("結束for迴圈")
}

break(跳出迴圈)

break語句可以結束forswitchselect的程式碼塊。

func breakDemo1() {
BREAKDEMO1:
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				break BREAKDEMO1
			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
	fmt.Println("...")
}

continue(繼續下次迴圈)

func continueDemo() {
forloop1:
	for i := 0; i < 5; i++ {
		// forloop2:
		for j := 0; j < 5; j++ {
			if i == 2 && j == 2 {
				continue forloop1
			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
}

陣列

陣列定義

var 陣列變數名 [元素數量]T

一旦定義,長度不能變

初始化
func main() {
	var testArray [3]int                        //陣列會初始化為int型別的零值
	var numArray = [3]int{1, 2}                 //使用指定的初始值完成初始化
	var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
	fmt.Println(testArray)                      //[0 0 0]
	fmt.Println(numArray)                       //[1 2 0]
	fmt.Println(cityArray)                      //[北京 上海 深圳]
}
func main() {
	var testArray [3]int
	var numArray = [...]int{1, 2}
	var cityArray = [...]string{"北京", "上海", "深圳"}
	fmt.Println(testArray)                          //[0 0 0]
	fmt.Println(numArray)                           //[1 2]
	fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
	fmt.Println(cityArray)                          //[北京 上海 深圳]
	fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}
func main() {
	a := [...]int{1: 1, 3: 5}
	fmt.Println(a)                  // [0 1 0 5]
	fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}
陣列遍歷
func main() {
	var a = [...]string{"北京", "上海", "深圳"}
	// 方法1:for迴圈遍歷
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i])
	}

	// 方法2:for range遍歷
	for index, value := range a {
		fmt.Println(index, value)
	}
}
多維陣列
func main() {
	a := [3][2]string{
		{"北京", "上海"},
		{"廣州", "深圳"},
		{"成都", "重慶"},
	}
	for _, v1 := range a {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}
}

北京	上海	
廣州	深圳	
成都	重慶

多維陣列只有第一層可以使用...來讓編譯器推導陣列長度。例如:

//支援的寫法
a := [...][2]string{
	{"北京", "上海"},
	{"廣州", "深圳"},
	{"成都", "重慶"},
}
//不支援多維陣列的內層使用...
b := [3][...]string{
	{"北京", "上海"},
	{"廣州", "深圳"},
	{"成都", "重慶"},
}
陣列是值型別

陣列是值型別,賦值和傳參會複製整個陣列。因此改變副本的值,不會改變本身的值。

func modifyArray(x [3]int) {
	x[0] = 100
}

func modifyArray2(x [3][2]int) {
	x[2][0] = 100
}
func main() {
	a := [3]int{10, 20, 30}
	modifyArray(a) //在modify中修改的是a的副本x
	fmt.Println(a) //[10 20 30]
	b := [3][2]int{
		{1, 1},
		{1, 1},
		{1, 1},
	}
	modifyArray2(b) //在modify中修改的是b的副本x
	fmt.Println(b)  //[[1 1] [1 1] [1 1]]
}

注意:

  1. 陣列支援 “==“、”!=” 操作符,因為記憶體總是被初始化過的。
  2. [n]*T表示指標陣列,*[n]T表示陣列指標 。

切片

一個擁有相同型別元素的可變長度的序列

定義

var name []T

長度/容量

通過使用內建的len()函式求長度,使用內建的cap()函式求切片的容量

len(s), cap(s)
使用make()函式建立構造切片
make([]T, size, cap)
T:切片的元素型別
size:切片中元素的數量
cap:切片的容量

a := make([]int, 2, 10)
fmt.Println(a)      //[0 0]
fmt.Println(len(a)) //2
fmt.Println(cap(a)) //10

判斷切片是否為空

請始終使用len(s) == 0來判斷,而不應該使用s == nil來判斷。

切片不能直接比較
切片賦值拷貝
s1 := make([]int, 3) //[0 0 0]
	s2 := s1             //將s1直接賦值給s2,s1和s2共用一個底層陣列
切片遍歷

遍歷方式和陣列是一致的

append
func main(){
	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]
}

var宣告的零值切片可以在append()函式直接使用,無需初始化。

s := []int{}  // 沒有必要初始化
s = append(s, 1, 2, 3)

var s = make([]int)  // 沒有必要初始化
s = append(s, 1, 2, 3)

追加切片

var citySlice []string
// 追加一個元素
citySlice = append(citySlice, "北京")
// 追加多個元素
citySlice = append(citySlice, "上海", "廣州", "深圳")
// 追加切片
a := []string{"成都", "重慶"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[北京 上海 廣州 深圳 成都 重慶]
copy
copy(destSlice, srcSlice []T)
srcSlice: 資料來源切片
destSlice: 目標切片
func main() {
	// copy()複製切片
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //使用copy()函式將切片a中的元素複製到切片c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}
刪除元素

沒有刪除切片元素的專用方法,我們可以使用切片本身的特性來刪除元素

從切片a中刪除索引為index的元素,操作方法是a = append(a[:index], a[index+1:]...)

func main() {
	// 從切片中刪除元素
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要刪除索引為2的元素
	a = append(a[:2], a[3:]...)
	fmt.Println(a) //[30 31 33 34 35 36 37]
}

map

map定義
map[KeyType]ValueType
KeyType:表示鍵的型別。
ValueType:表示鍵對應的值的型別。

map型別的變數預設初始值為nil,需要使用make()函式來分配記憶體。語法為:

make(map[KeyType]ValueType, [cap])
基本使用
func main() {
	scoreMap := make(map[string]int, 8)
	scoreMap["張三"] = 90
	scoreMap["小明"] = 100
	fmt.Println(scoreMap)
	fmt.Println(scoreMap["小明"])
	fmt.Printf("type of a:%T\n", scoreMap)
}

map[小明:100 張三:90]
100
type of a:map[string]int


map也支援在宣告的時候填充元素
func main() {
	userInfo := map[string]string{
		"username": "沙河小王子",
		"password": "123456",
	}
	fmt.Println(userInfo) //
}
判斷某個鍵是否存在
value, ok := map[key]
func main() {
	scoreMap := make(map[string]int)
	scoreMap["張三"] = 90
	scoreMap["小明"] = 100
	// 如果key存在ok為true,v為對應的值;不存在ok為false,v為值型別的零值
	v, ok := scoreMap["張三"]
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("查無此人")
	}
}
map遍歷
func main() {
	scoreMap := make(map[string]int)
	scoreMap["張三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	for k, v := range scoreMap {
		fmt.Println(k, v)
	}
}

遍歷map時的元素順序與新增鍵值對的順序無關。

delete
delete(map, key)
func main(){
	scoreMap := make(map[string]int)
	scoreMap["張三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	delete(scoreMap, "小明")//將小明:100從map中刪除
	for k,v := range scoreMap{
		fmt.Println(k, v)
	}
}
按照指定順序遍歷map
func main() {
	rand.Seed(time.Now().UnixNano()) //初始化隨機數種子

	var scoreMap = make(map[string]int, 200)

	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("stu%02d", i) //生成stu開頭的字串
		value := rand.Intn(100)          //生成0~99的隨機整數
		scoreMap[key] = value
	}
	//取出map中的所有key存入切片keys
	var keys = make([]string, 0, 200)
	for key := range scoreMap {
		keys = append(keys, key)
	}
	//對切片進行排序
	sort.Strings(keys)
	//按照排序後的key遍歷map
	for _, key := range keys {
		fmt.Println(key, scoreMap[key])
	}
}
元素為map型別的切片
func main() {
	var mapSlice = make([]map[string]string, 3)
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
	fmt.Println("after init")
	// 對切片中的map元素進行初始化
	mapSlice[0] = make(map[string]string, 10)
	mapSlice[0]["name"] = "小王子"
	mapSlice[0]["password"] = "123456"
	mapSlice[0]["address"] = "沙河"
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
}
值為切片型別的map
func main() {
	var sliceMap = make(map[string][]string, 3)
	fmt.Println(sliceMap)
	fmt.Println("after init")
	key := "中國"
	value, ok := sliceMap[key]
	if !ok {
		value = make([]string, 0, 2)
	}
	value = append(value, "北京", "上海")
	sliceMap[key] = value
	fmt.Println(sliceMap)

高顏值後臺管理系統免費使用 ### 子楓後臺管理系統 ###,可在寶塔面板直接安裝

歡迎關注我的公眾號:子楓的奇妙世界,獲得獨家整理的學習資源和日常乾貨推送。
如果您對我的其他專題內容感興趣,直達我的個人部落格:www.wangmingchang.com