• Golang基础-面向过程篇


    基本语法

    go语言输出hello world的语法如下

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	fmt.Println("hello world")
    	time.Sleep(1 * time.Second)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    变量

    go的变量定义语法共有四种。第一种是var [变量名] [变量类型] = [变量值],如果不写变量值,那么默认值就是0。

    var a int
    fmt.Println("a=", a)
    fmt.Printf("type of a=%T\n", a)
    
    • 1
    • 2
    • 3

    第二种是声明变量时指定值

    var b int = 100
    fmt.Println("b=", b)
    fmt.Printf("type of b=%T\n", b)
    
    • 1
    • 2
    • 3

    第三种是声明一个变量,省略数据类型,由go自己判断

    var c = 100
    fmt.Println("c=", c)
    
    • 1
    • 2

    第四种是省略var,自动匹配

    e := 100
    fmt.Println("e=", e)
    fmt.Printf("type of e=%T\n", e)
    
    • 1
    • 2
    • 3

    声明全局变量

    package main
    
    import "fmt"
    
    // 声明全局变量 方法123是可以的
    var gA int = 100
    var gB = 200
    
    func main() {
    	fmt.Println("gA=", gA)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在定义变量时,还可以定义多个

    var xx, yy int = 100, 200
    fmt.Println("xx=", xx, "yy=", yy)
    
    var (
    	vv int  = 100
    	jj bool = true
    )
    fmt.Println("vv=", vv, "jj=", jj)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    常量

    常量用const关键字来声明

    const length int = 10
    fmt.Println("length=", length)
    
    • 1
    • 2

    除此之外,还能批量声明

    const (
    	BEIJING = 1
    	SHANGHAI = 2
    	SHENZHENG = 3
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在go中有一个iota关键字,可以用来自动赋值。可以在const()中添加关键字iota,每行iota都会累加1,第一行默认是0,只能在const中使用

    package main
    
    import "fmt"
    
    const (
    	//	可以在const()中添加关键字iota,每行iota都会累加1,第一行默认是0,只能在const中使用
    	BEIJING = iota * 10
    	SHANGHAI
    	SHENZHENG
    )
    
    func main() {
    	//常量(只读)
    	const length int = 10
    
    	fmt.Println("length=", length)
    
    	fmt.Println("beijing=", BEIJING) // 0
    	fmt.Println("shanghai=", SHANGHAI) // 10
    	fmt.Println("shenzheng=", SHENZHENG) // 20
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    函数

    go中函数定义

    func foo1(a string, b int) int {
    	fmt.Println("a=", a)
    	fmt.Println("b=", b)
    	c := 10
    	return c
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果函数有多个返回值时

    func foo2(a string, b int) (int, int) {
    	fmt.Println("a=", a)
    	fmt.Println("b=", b)
    	return 666, 777
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当返回多个有形参名的,如果类型相同,可以省略一个,且形参默认值为0

    func foo3(a string, b int) (r1, r2 int) {
    	r1 = 1000
    	r2 = 2000
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    import导包

    go中import导包的具体过程如下图所示
    请添加图片描述
    现在创建如下目录结构

    ./gostudy/5-init/
    |____lib2
    | |____lib2.go
    |____lib1
    | |____lib1.go
    |____main.go
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    lib1/2.go内容

    package lib1
    
    import "fmt"
    
    // 当前lib1提供的API
    func Lib1Test() {
    	fmt.Println("Lib1Test() ...")
    }
    
    func init() {
    	fmt.Println("lib1.init() ...")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此时导包代码如下

    package main
    
    import(
    	"gostudy/5-init/lib1"
    	"gostudy/5-init/lib2"
    )
    
    func main() {
    	lib1.Lib1Test()
    	lib2.Lib2Test()	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    匿名导包

    在导入包后如果不使用它,在编译时会直接报错,想要解决就需要通过匿名导包,即_ 包名

    import (
    	_ "gostudy/5-init/lib1"
    	mylib2 "gostudy/5-init/lib2" // 给包起别名
    )
    
    • 1
    • 2
    • 3
    • 4

    指针

    package main
    
    import "fmt"
    
    func changeValue(p *int) {
    	*p = 10
    }
    
    func main() {
    	var a int = 1
    	changeValue(&a)
    	fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    程序运行后,a的值被改为10

    defer

    在 Go 语言中,defer 关键字用于延迟执行一个函数调用,通常被用于确保一些操作在函数执行结束时得以执行,无论函数是通过正常返回还是发生了运行时恐慌(panic)。

    defer 语句将函数调用推迟到包含 defer 语句的函数即将返回时执行。defer 语句经常用于资源清理、关闭文件、解锁资源等操作。
    defer 语句的执行顺序是后进先出(LIFO),即最后一个 defer 语句最先执行。

    package main
    
    import "fmt"
    
    func func1() {
    	fmt.Println("A")
    }
    
    func func2() {
    	fmt.Println("B")
    }
    
    func func3() {
    	fmt.Println("C")
    }
    
    func main() {
    	defer func1()
    	defer func2()
    	defer func3()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    以上代码的最终执行结果为CBA

    静态数组

    定义固定长度的数组并遍历

    package main
    
    import "fmt"
    
    func main() {
    	//固定长度的数组
    	var MyArray1 [10]int
    	for i := 0; i < len(MyArray1); i++ {
    		fmt.Println(MyArray1[i])
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    另一种定义和遍历方式

    package main
    
    import "fmt"
    
    func main() {
    	MyArray2 := [10]int{1, 2, 3, 4}
    	for index, value := range MyArray2 {
    		fmt.Println("index =", index, ",value =", value)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    动态数组(slice)

    go语言中动态数组是通过切片(slice)来实现的,切片的长度可以动态增长或缩小,这使得切片更加灵活,可以根据实际需要动态调整大小。

    定义方式

    MyArray := []int{1, 2, 3, 4}
    
    • 1

    往函数中传参并在函数中修改数组的第一个元素

    package main
    
    import "fmt"
    
    func printArray(MyArray []int) {
    	// _表示匿名变量
    	for _, value := range MyArray {
    		fmt.Println("value=", value)
    	}
    	MyArray[0] = 100
    }
    
    func main() {
    	MyArray := []int{1, 2, 3, 4}
    	printArray(MyArray)
    	fmt.Println("===========")
    	for _, value := range MyArray {
    		fmt.Println("value=", value)
    	}
    }
    // value= 1
    // value= 2
    // value= 3
    // value= 4
    ===========
    // value= 100
    // value= 2
    // value= 3
    // value= 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    slice的定义方式共有四种,方式一:声明slice1是一个切片,并且初始化,默认值是1,2,3

    slice1 := []int{1, 2, 3}
    
    • 1

    方式二:声明slice是切片,但是没有分配空间。此时如果想要赋值会报错,需要通过make来分配空间

    var slice1 []int
    slice1 = make([]int, 3)
    
    • 1
    • 2

    方式三:声明slice是切片,同时给slice分配空间,3个空间,初始化为0

    var slice1 []int = make([]int, 3)
    
    • 1

    方式四:通过:=推导出是一个slice

    slice1 := make([]int, 3)
    
    • 1

    想要判断一个切片是否被分配空间,可以用nil来判断

    package main
    
    import "fmt"
    
    func main() {
    	var slice1 []int
    	if slice1 == nil {
    		fmt.Println("slice未被初始化")
    	} else {
    		fmt.Println("slice有空间")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    slice追加元素

    定义如下slice,创建了一个切片 numbers,使用 make 函数初始化一个长度为 3、容量为 5 的整数切片。

    • 长度 (len) 是切片当前包含的元素数量,这里是 3。
    • 容量 (cap) 是切片底层数组的大小,这里是 5。
    • 切片本身存储了一个指向底层数组的指针,以及长度和容量的信息。
    package main
    
    import "fmt"
    
    func main() {
    	var numbers = make([]int, 3, 5)
    	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
    }
    // len=3,cap=5,slice=[0 0 0]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如下图所示
    请添加图片描述
    此时想用如下代码向slice中增加元素,输出的结果为len=4,cap=5,slice=[0 0 0 1]

    numbers = append(numbers, 1)
    fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
    
    • 1
    • 2

    当追加元素到超过数组的cap时,由于容量不足,底层数组扩展为新的容量(原容量的两倍)

    package main
    
    import "fmt"
    
    func main() {
    	var numbers = make([]int, 3, 5)
    	numbers = append(numbers, 1)
    	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
    	numbers = append(numbers, 2)
    	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
    	numbers = append(numbers, 6)
    	fmt.Printf("len=%d,cap=%d,slice=%v\n", len(numbers), cap(numbers), numbers)
    }
    /* 输出结果
    len=4,cap=5,slice=[0 0 0 1]
    len=5,cap=5,slice=[0 0 0 1 2]
    len=6,cap=10,slice=[0 0 0 1 2 6]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    以上代码的执行过程如下:

    1. 初始时,切片 numbers 的长度是 3,容量是 5,内容是 [0 0 0]。
    2. 向切片追加元素 1,长度变为 4,容量仍然是 5,内容变为 [0 0 0 1]。由于容量未超过预分配的容量,底层数组未发生扩展。
    3. 向切片追加元素 2,长度变为 5,容量仍然是 5,内容变为 [0 0 0 1 2]。
    4. 向切片追加元素 6,由于容量不足,底层数组扩展为新的容量(原容量的两倍,即 5*2=10)。切片的长度变为 6,容量变为 10,内容变为 [0 0 0 1 2 6]。

    slice截取

    和Python类似

    s := []int{1, 2, 3}
    s1 := s[0:2] // [1,2]
    
    • 1
    • 2

    代码创建了一个切片 s 包含元素 [1, 2, 3],然后通过 s[0:2] 的切片操作创建了一个新的切片 s1,该切片包含 s 的索引 0 到 1 的元素。这样的切片操作是左闭右开的,所以 s1 将包含索引 0 和 1 对应的元素,即 [1, 2]。

    需要注意的是这个切片操作是基于原始切片 s 的,所以对 s1 的修改也会反映在 s 中,因为s和s1的指针指向的是同一个地址,新切片和原始切片共享相同的底层数组。例如,如果你修改了 s1 中的元素,s 中对应的元素也会被修改。通过以下代码执行的结果可以看出。

    package main
    
    import "fmt"
    
    func main() {
    	s := []int{1, 2, 3}
    
    	s1 := s[0:2] // [1,2]
    	s1[0] = 100
    	fmt.Println(s)
    	fmt.Println(s1)
    }
    /*输出结果
    [100 2 3]
    [100 2]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果想把数组内容拷贝到另一个地址的数组中,可以用copy来进行深拷贝。如果 s2 的长度小于 s 的长度,copy 将只复制 s2 的长度个元素。

    package main
    
    import "fmt"
    
    func main() {
    	s := []int{1, 2, 3}
    
    	s1 := s[0:2] // [1,2]
    	s[0] = 100
    
    	//copy深拷贝
    	s2 := make([]int, 3)
    	copy(s2, s)
    	s[0] = 50
    	fmt.Println(s)
    	fmt.Println(s1)
    	fmt.Println(s2)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    以上代码开辟了新的数组空间s2,并把s数组copy到s2中,即使把s中第一个元素的值改为50,s2也不受影响,而s1会跟随s也改为50。

    map

    在Go语言中,map 是一种用于存储键值对的数据结构,也被称为字典或关联数组。

    定义方式

    map的定义方式共有三种。

    第一种:声明MyMap1是一种map类型,key和value都是string。在声明后使用make函数为MyMap1分配了空间,并指定了容量为10。

    var MyMap1 map[string]string
    if MyMap1 == nil {
    	fmt.Println("MyMap1是一个空map")
    }
    // 分配空间
    MyMap1 = make(map[string]string, 10)
    
    MyMap1["one"] = "java"
    MyMap1["two"] = "c++"
    MyMap1["three"] = "go"
    
    fmt.Println(MyMap1)
    /*输出结果
    map[one:java three:go two:c++]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在最终输出时,由于map是无序的,键值对的顺序可能会不同。

    第二种:直接使用make为map创建空间

    MyMap2 := make(map[int]string)
    MyMap2[1] = "java"
    MyMap2[2] = "c++"
    MyMap2[3] = "go"
    fmt.Println(MyMap2)
    /*输出结果
    map[1:java 2:c++ 3:go]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    第三种:在声明map时直接定义其中的键值对

    MyMap3 := map[string]string{
    	"one":   "php",
    	"two":   "c",
    	"three": "python",
    }
    fmt.Println(MyMap3)
    /*输出结果
    map[one:php three:python two:c]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    map使用方式

    map的增删改查实现如下:

    package main
    
    import "fmt"
    
    func main() {
    	cityMap := make(map[string]string)
    
    	//添加
    	cityMap["China"] = "beijing"
    	cityMap["Japan"] = "Tokyo"
    	cityMap["USA"] = "NewYork"
    
    	//遍历
    	for key, value := range cityMap {
    		fmt.Println("key =", key)
    		fmt.Println("value =", value)
    	}
    
    	//删除
    	delete(cityMap, "China")
    
    	//修改
    	cityMap["USA"] = "DC"
    
    	fmt.Println("===========")
    
    	for key, value := range cityMap {
    		fmt.Println("key =", key)
    		fmt.Println("value =", value)
    	}
    }
    /*输出结果
    key = China
    value = beijing
    key = Japan
    value = Tokyo
    key = USA
    value = NewYork
    ===========
    key = Japan
    value = Tokyo
    key = USA
    value = DC
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    函数传参,通过定义了一个名为 printMap 的函数,该函数接受一个 map[string]string 类型的参数 cityMap,并在循环中遍历该 map 输出每个键值对的键和值。以下代码的输出结果同上。

    package main
    
    import "fmt"
    
    func printMap(cityMap map[string]string) {
    	for key, value := range cityMap {
    		fmt.Println("key =", key)
    		fmt.Println("value =", value)
    	}
    }
    
    func main() {
    	cityMap := make(map[string]string)
    
    	//添加
    	cityMap["China"] = "beijing"
    	cityMap["Japan"] = "Tokyo"
    	cityMap["USA"] = "NewYork"
    	
    	printMap(cityMap)
    
    	//删除
    	delete(cityMap, "China")
    
    	//修改
    	cityMap["USA"] = "DC"
    
    	fmt.Println("===========")
    
    	printMap(cityMap)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    需要注意的是,向函数中传递的cityMap是一个引用传递,因此两个map指向的是同一个地址空间,在函数内对 map 的修改会影响到原始的 map。

    package main
    
    import "fmt"
    
    func printMap(cityMap map[string]string) {
    	for key, value := range cityMap {
    		fmt.Println("key =", key)
    		fmt.Println("value =", value)
    	}
    }
    
    func changeValue(cityMap map[string]string) {
    	cityMap["UK"] = "London"
    }
    
    func main() {
    	cityMap := make(map[string]string)
    
    	//添加
    	cityMap["China"] = "beijing"
    	cityMap["Japan"] = "Tokyo"
    	cityMap["USA"] = "NewYork"
    
    	printMap(cityMap)
    
    	//删除
    	delete(cityMap, "China")
    
    	//修改
    	cityMap["USA"] = "DC"
    	changeValue(cityMap)
    
    	fmt.Println("===========")
    
    	for key, value := range cityMap {
    		fmt.Println("key =", key)
    		fmt.Println("value =", value)
    	}
    }
    /*输出结果
    key = USA
    value = NewYork
    key = China
    value = beijing
    key = Japan
    value = Tokyo
    ===========
    key = UK
    value = London
    key = Japan
    value = Tokyo
    key = USA
    value = DC
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    Kotlin高阶函数&DSL布局劝退指南
    Windows 安装 MySQL 5.7详细步骤
    基于多种GPU和CPU进行优化可选,最新基于机器学习模型单图换脸离线版软件包及使用方法,本地离线版本模型一键运行(免费下载)
    typescript17-函数可选参数
    2023年高校大数据实验室建设方案
    期货开户是否有资金门槛?
    KR万能公式
    Jenkins 持续集成:Linux 系统 两台机器互相免密登录
    第三章:Spring常用注解解释
    socket can查看详细信息 命令 ip -details -statistics link show can0
  • 原文地址:https://blog.csdn.net/weixin_46270220/article/details/134514081