• Go语言笔记-基础篇


    视频(P1-P49):【狂神说】Go语言零基础学习视频通俗易懂

    1. 安装

    去 Go语言中文网下载安装包,一路下一步。然后配置环境变量 GOROOTGOPATH

    GOROOT=D:\env\Go # Go的安装目录
    GOPATH=D:\env\GOWorks # Go项目存储的路径
    
    • 1
    • 2

    GOPATH 里面需要包含 src, pkg, bin 三个目录

    2. Hello World

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println("Hello World")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 一个程序只能有一个main包,用package关键字

    2. 需要 导入 fmt

    3. 写一个main函数(主入口)

    4. go run hello.go 来运行

    如果在GoLand里报错,可以用命令行输入后解决

    go env -w GO111MODULE=off
    
    • 1

    3. 注释

    package main
    
    import "fmt"
    // 单行注释
    /* 
    多行注释
    多行注释
    */
    func main() {
    	fmt.Println("Hello World")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4. 变量

    变量定义:var name type,变量会有缺省值

    image-20221111202802870

    // var 变量名 变量类型 = 值
    var name string = "kuangshen"
    name = "zhangsan"
    
    • 1
    • 2
    • 3

    多个变量定义:

    var (
    	name string
    	age int
    	addr string
    )
    
    fmt.Println(name, age, addr)
    
    var a,b,c int
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    变量应为驼峰命名法

    变量赋值

    var (
    	name string
    	age int
    	addr string
    )
    name = "kuangshen"
    age = 25
    addr = "zhongguo"
    
    fmt.Println(name, age, addr)
    var a,b,c int
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    短变量声明并初始化

    • 定义变量的时候必须初始化
    name := "kuangshen"
    age := 18
    
    fmt.Println(name, age)
    
    • 1
    • 2
    • 3
    • 4

    打印变量的类型:

    name := "kuangshen"
    age := 18
    
    fmt.Printf("%T,%T", name, age)
    
    • 1
    • 2
    • 3
    • 4

    获取变量的地址:

    var num int
    num = 100
    fmt.Printf("num: %d, 内存地址: %p", num, &num)
    
    // num: 100, 内存地址: 0xc00001c088
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Go语言变量变换

    var a int = 100
    var b int = 200
    
    b, a = a, b
    // 200 100
    
    • 1
    • 2
    • 3
    • 4
    • 5

    匿名变量 _

    package main
    
    import "fmt"
    
    func test() (int, int) {
    	return 100, 200
    }
    func main() {
    	a, _ := test() // 用 _接收,方便废弃
    	fmt.Println(a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    变量的作用域:

    • 全局变量:放置在函数之外的
    • 局部变量:放置在函数之内的

    如果全局变量和局部变量同名,在局部变量所在作用域使用时,取到的是局部变量

    5. 常量

    定义方式:const name [type] = value

    类型可以自动推导,无需声明类型

    多个常量定义:

    const a,b,c = 3.14, "abc", 110
    
    • 1

    iota,特殊常量,go语言的常量计数器

    package main
    
    import "fmt"
    
    func main() {
    	const (
    		a = iota
    		b = iota
    		c = iota
    	)
    
    	fmt.Println(a, b, c)
    }
    // 0 1 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    第一个定义 iota,后面不赋值默认为iota,其他值同理

    package main
    
    import "fmt"
    
    func main() {
    	const (
    		a = iota
    		b
    		c
    		d = "haha"
    		e
    		f = 100
    		g
    		h = iota
    		i
    	)
        const (
        	j = iota
            k
        )
    	fmt.Println(a, b, c, d, e, f, g, h, i)
        // 0 1 2 haha haha 100 100 7 8
        fmt.Println(j, k)
        // 0 1
    
    }
    
    
    • 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

    6. 数据类型

    6.1 布尔型 bool

    true or false

    6.2 数字型

    image-20221111205808705

    image-20221111205925043

    6.3 字符型

    单引号字符,双引号字符串

    7. 数据类型转换

    在Go里不存在隐性类型转换,所有的转换必须是显式

    转换后的变量 := 要转换的类型(变量)
    
    • 1
    package main
    
    import "fmt"
    
    func main() {
    	a := 3
    	b := 5.0
    	fmt.Printf("%T ", a)
    	fmt.Printf("%T ", b)
    
    	// 需求:将int类型的a转换为 float64类型 类型转换
    	c := float64(a)
    	d := int(b)
    	
    	fmt.Printf("%T ", c)
    	fmt.Printf("%T ", d)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    类型转换只能在定义正确的情况下转换成功,例如从一个取值范围较小的类型转换到一个取值范围较大的类型(将int16转换为int32)。当从一个取值范围较大的类型转换到取值范围较小的类型时(将int32转换为int16或将float32转换为int),会发生精度丢失(截断)的情况.

    8. 算数运算符

    8.1 算数运算符

    image-20221111210959504

    重点:++、–是语句而不是表达式!

    8.2 关系运算符

    image-20221111211100908

    关系运算符表达式的结果都是bool

    8.3 逻辑运算符

    image-20221111211224926

    逻辑运算符表达式的结果都是bool

    8.4 位运算

    image-20221111211322811

    8.5 赋值运算符

    image-20221111211359136

    9. 键盘输入输出

    fmt.Scanf()fmt.Scan()fmt.Scanln()

    package main
    
    import "fmt"
    
    func main() {
    	var x int
    	var y float64
    	// 定义了两个变量
    	fmt.Println("请输入两个数1.整数2.浮点数")
    	fmt.Scanln(&x, &y)
    	fmt.Println(x, y)
    }
    
    /*
    请输入两个数1.整数2.浮点数
    1 3.14
    1 3.14
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    /*
    请输入两个数1.整数2.浮点数
    1 3.14
    1 3.14
    */

    
    
    
    ## 10. 流程控制
    
    ### 10.1 if
    
    ```go
    if condition {
    
    } else if condition2 {
    
    } else {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    10.2 switch

    默认switch每个case是不需要break的(不像其他语句)

    package main
    
    import "fmt"
    
    func main() {
    	var score int = 90
    
    	switch score {
    	case 90:
    		fmt.Println("A")
    	case 80:
    		fmt.Println("B")
    	case 50, 60, 7:
    		fmt.Println("C")
    	default:
    		fmt.Println("D")
    	}
    	// 默认为 bool = true
    	switch {
    	case false:
    		fmt.Println("false")
    	case true:
    		fmt.Println("true")
    	default:
    		fmt.Println("default")
    	}
    }
    // A
    // true
    
    • 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

    穿透 fallthrough

    package main
    
    import "fmt"
    
    func main() {
    	a := false
    	switch a {
    	case false:
    		fmt.Println("1. case 条件为 false")
    		fallthrough
    	case true:
    		fmt.Println("2. case 条件为 true")
    	}
    }
    // 1. case 条件为 false
    // 2. case 条件为 true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    10.3 select

    10.4 channel

    11. for循环

    11.1 for 起始;循环条件;控制变量

    package main
    
    import "fmt"
    
    func main() {
    	for i := 1; i < 10; i++ {
    		fmt.Print(i, ",")
    	}
    }
    // 1,2,3,4,5,6,7,8,9,
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    11.2 for ;循环条件;

    同其他语言的 while

    11.3 for {}

    for true {}

    12. string的用法

    Go语言中,字符串是字节的切片,是Unicode兼容的,并且UTF8

    获取子字符串的长度:len(str)

    string 是不能修改的

    str := "hello,xuexiangban"
    fmt.Println(str)
    
    // 字符串的长度
    fmt.Println("字符串的长度为: ", len(str))
    
    // 获取指定的字节
    fmt.Printf("%c\n", str[0])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    两种方式遍历字符串

    // str.for
    // for
    for i := 0; i < len(str); i++ {
    	fmt.Printf("%c", str[i])
    }
    
    // for range
    for i, v := range str {
    	fmt.Print(i)
    	fmt.Printf("%c", v)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    13. 函数

    func 函数名([参数列表]) [返回值列表] {
    	函数体
    }
    
    • 1
    • 2
    • 3
    package main
    
    import "fmt"
    
    func main() {
    	printInfo()
    	myPrint("haha")
    	fmt.Println(add2(1, 2))
    	x, y := swap("学相伴", "狂神说")
    	fmt.Println(x, y)
    
    }
    
    // 无参无返回值
    func printInfo() {
    	fmt.Println("printInfo")
    }
    
    // 有参的函数
    func myPrint(str string) {
    	fmt.Println(str)
    }
    
    // 有一个返回值
    func add2(a, b int) int {
    	return a + b
    }
    
    // 有多个返回值的函数
    func swap(a, b string) (string, string) {
    	return b, a
    }
    
    • 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

    可变参数:…

    package main
    
    import "fmt"
    
    func main() {
    	fmt.Println(getSum(1, 2, 3))
    }
    
    func getSum(nums ...int) int {
    	sum := 0
    	for i := range nums {
    		sum += i
    	}
    	return sum
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    参数传递

    • 值类型的数据:操作数据本身,intstringboolarray
    • 引用数据类型:操作的是数据的地址:slicemapchan

    值传递:传递的是数据的副本

    package main
    
    import "fmt"
    
    func main() {
    	// 值传递
    	arr := [4]int{1, 2, 3, 4}
    	fmt.Println(arr)
    	update(arr)
    	fmt.Println("调用后修改的数据", arr)
    }
    
    func update(arr2 [4]int) {
    	fmt.Println("arr2接收时的数据", arr2)
    	arr2[0] = 100
    	fmt.Println("arr2接收后的数据", arr2)
    }
    
    /*
    [1 2 3 4]
    arr2接收时的数据 [1 2 3 4]
    arr2接收后的数据 [100 2 3 4]
    调用后修改的数据 [1 2 3 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

    引用传递

    切片,可以扩容的数组

    package main
    
    import "fmt"
    
    func main() {
    	s1 := []int{1, 2, 3, 4}
    	update2(s1)
    	fmt.Println("调用后的数据", s1)
    }
    
    func update2(s2 []int) {
    	fmt.Println("传递的数据", s2)
    	s2[0] = 100
    	fmt.Println("修改后的数据", s2)
    }
    /*
    传递的数据 [1 2 3 4]
    修改后的数据 [100 2 3 4]
    调用后的数据 [100 2 3 4]
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    14. defer

    defer语义:推迟、延迟

    package main
    
    import "fmt"
    
    func main() {
    	f(" 1 ")
    	fmt.Print(" 2 ")
    	defer f(" 3 ")
    	fmt.Print(" 4 ")
    	defer f(" 5 ")
    	fmt.Print(" 6 ")
    	defer f(" 7 ")
    }
    
    func f(s string) {
    	fmt.Printf(" %s ", s)
    }
    /*
      1   2  4  6   7    5    3
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    defer如果传参,虽然延迟执行,但是传参是已经执行的状态

    package main
    
    import "fmt"
    
    func main() {
    	a := 10
    	fmt.Println("a=", a)
    	defer f(a) // 此时参数已经传进去了!
    	a++
    	fmt.Println("end a=", a)
    }
    
    func f(s int) {
    	fmt.Printf(" %d ", s)
    }
    /*
    a= 10
    end a= 11
     10
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    15. 函数的本质

    1. 函数本身就是一种类型
    2. 函数的类型是它的函数原型
    package main
    
    import "fmt"
    
    func main() {
    	fmt.Printf("%T", f1)
    }
    func f1(a, b int) int {
    	return a + b
    }
    /*
    func(int, int) int
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 函数加上() 为调用,不加() 以变量形式存在
    package main
    
    import "fmt"
    
    func main() {
    	var f5 func(int, int) int
    	f5 = f1
    	fmt.Println(f5)
    	fmt.Println(f1)
    	f5(1, 2)
    }
    func f1(a, b int) int {
    	return a + b
    }
    /*
    0x67e560
    0x67e560
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    函数在Go语言中是复合类型,可以看做是一种特殊的变量。

    函数名():调用返回结果

    函数名:指向函数体的内存地址,一种特殊类型的指针变量

    匿名函数

    package main
    
    import "fmt"
    
    func main() {
    	func(a, b int) {
    		fmt.Print(a, b)
    		fmt.Println("我是f3")
    	}(1, 2)
    }
    /*
    1 2我是f3
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    回调参数

    package main
    
    import "fmt"
    
    func main() {
    	r1 := add(1, 2)
    	fmt.Println(r1)
    
    	r2 := oper(3, 4, add)
    	fmt.Println(r2)
    
    	r3 := oper(8, 4, sub)
    	fmt.Println(r3)
    
    	r4 := oper(8, 4, func(a int, b int) int {
    		if b == 0 {
    			fmt.Println("除数不能为0")
    			return 0
    		}
    		return a / b
    	})
    	fmt.Println(r4)
    }
    
    // 高阶函数
    func oper(a, b int, fun func(int, int) int) int {
    	return fun(a, b)
    }
    
    func add(a, b int) int {
    	return a + b
    }
    
    func sub(a, b int) int {
    	return a - b
    }
    /*
    3
    7
    4
    2
    */
    
    • 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

    闭包

    一个外层函数中,有内层函数,该内层函数中,会操作外层函数的局部变量并且该外层函数的返回值就是这个内层函数。这个内层函数和外层函数的局部变量,统称为闭包结构

    局部变量的生命周期就会发生改变,正常的局部变量会随着函数的调用而创建,随着函数的结束而销毁,但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁,因为内层函数还在继续使用

    package main
    
    import "fmt"
    
    func main() {
    	r1 := increment()
    	fmt.Println(r1)
    	v1 := r1()
    	fmt.Println(v1)
    	v2 := r1()
    	fmt.Println(v2)
    
    }
    
    func increment() func() int {
    	i := 0
    	fun := func() int {
    		i++
    		return i
    	}
    	return fun
    }
    /*
    0x102e5e0
    1
    2
    */
    
    • 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

    16. 泛型

    16.1. 什么是泛型

    package main
    
    import "fmt"
    
    func main() {
    	strs := []string{"xuexiangban", "kuangshen"}
    	printArray(strs)
    }
    
    // []T 形式类型, 实际类型
    /*
    
    内置的泛型类型: any 和 comparable
    - any: 表示go里面所有的内置基本类型,等价于 interface{}
    - comparable: 表示go里面所有内置的可比较类型:int, uint, float, bool, struct, 指针
    
    */
    func printArray[T string | int](arr []T) {
    	// 类型断言 x.(T)
    	for _, a := range arr {
    		fmt.Print(a)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    泛型减少重复代码并提高类型安全性。

    16.2. 泛型类型

    type slice[T int|float32|float64] []T
    
    • 1
    • T就是类型形参,类似占位符
    • int|float32|float64 是类型约束,告诉编译器,只能接受int或float32或float64这三种类型的实参
    • 中括号里的内容为类型形参列表
    package main
    
    import "fmt"
    
    func main() {
    	type Slice[T int | float64 | float32] []T
    
    	var a Slice[int] = []int{1, 2, 3}
    	var b Slice[float32] = []float32{1, 2, 3}
    	var c Slice[float64] = []float64{1, 2, 3}
    	fmt.Print(a)
    	fmt.Print(b)
    	fmt.Print(c)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这里b可以赋值给a吗?不可以。

    下面是map的泛型示例:

    	type MyMap[KEY int | string, VALUE float64] map[KEY]VALUE
    	var m1 MyMap[string, float64] = map[string]float64{
    		"go":   9.9,
    		"java": 9.0,
    	}
    
    	fmt.Print(m1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    一种特殊泛型:

    type Wow[T int|string] int;
    	var a Wow[int] = 123 // OK
    	var b Wow[string] = 123 // OK
    	var c Wow[string] = "123" // ERROR
    
    • 1
    • 2
    • 3
    • 4

    16.3 泛型receiver

    package main
    
    import "fmt"
    
    type MySlice[T int | float64] []T
    
    // 给泛型添加方法
    func (s MySlice[T]) Sum() T {
    	var sum T
    	for _, v := range s {
    		sum += v
    	}
    	return sum
    }
    
    func main() {
    	var s MySlice[int] = []int{1, 2, 3, 4}
    	fmt.Print(s.Sum())
    
    	var f MySlice[float64] = []float64{1.0, 2.1, 3.3, 4.5}
    	fmt.Print(f.Sum())
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    16.4 泛型函数

    package main
    
    import "fmt"
    
    func Add[T int | float64 | string](a T, b T) T {
    	return a + b
    }
    
    func main() {
    	res := Add[int](1, 2)
    	fmt.Print(res)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    16.5 自定义泛型约束

    package main
    
    type MyInt interface {
    	int | int8 | int16 | int32 | int64
    }
    
    func GetMaxNum[T MyInt](a, b T) T {
    	if a > b {
    		return a
    	} else {
    		return b
    	}
    
    }
    
    func main() {
    	var a int = 10
    	var b int = 20
    
    	GetMaxNum(a, b)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    如果我们创建了一个 int 类型的别名类型 intAAA,这时候如果MyInt里没有intAAA,就会报错。

    解决方案1:把intAAA加到MyInt的定义里。
    解决方案2:在int的左边加一个~

  • 相关阅读:
    SAS 数值存储方式和精度问题
    灰色预测MATLAB程序
    289. 生命游戏 Python
    anroid html5 拍照扫码
    MySQL8修改密码
    C++ Reference: Standard C++ Library reference: Containers: deque: deque: clear
    N32学习笔记2-GPIO使用和关闭JTAG打开SW调试模式
    4.6函数的简单解释
    无法通过ssh连接到主机:root@node1:权限被拒绝
    Oracle数据库使用PLSQL-Developer15导出导入Excel文件
  • 原文地址:https://blog.csdn.net/okfang616/article/details/127813462