go學習筆記1
hello GO
這裡使用vscode
-
安裝外掛go
-
新建hello資料夾,建立main.go檔案
package main import "fmt" func main(){ fmt.Println("Hello") }
-
開啟命令列
-
-
執行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語言支援兩種浮點型數:float32
和float64
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(假)
兩個值。
注意:
- 布林型別變數的預設值為
false
。 - Go 語言中不允許將整型強制轉換為布林型.
- 布林型無法參與數值運算,也無法與其他型別進行轉換。
字串
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型別
字元用單引號(’)包裹起來
nt8
型別,或者叫 byte 型,代表了ASCII碼
的一個字元。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才為1) | 參與運算的兩數各對應的二進位相或。 (兩位有一個為1就為1) ^ 參與運算的兩數各對應的二進位相異或,當兩對應的二進位相異時,結果為1。 (兩位不一樣則為1) << 左移n位就是乘以2的n次方。 “a<<b”是把a的各二進位全部左移b位,高位丟棄,低位補0。 >> 右移n位就是除以2的n次方。 “a>>b”是把a的各二進位全部右移b位。 -
賦值運算子
= += -= *= /= %= <<= >>= &= |= ^=
流程控制
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
語句可以結束for
、switch
和select
的程式碼塊。
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]]
}
注意:
- 陣列支援 “==“、”!=” 操作符,因為記憶體總是被初始化過的。
[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 。