跳转至

Golang

导包

Go
import (
    "fmt"
    // "strconv"
    "gomod-code/v1/mod/publicfunc"
    // 导入自定义的包,前面需加上 go.mod 内的路径
    "errors"
)

// 标志符的使用
// 下划线 "_" 本身在 Go 中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但是它对应的值会被忽略(比如: 忽略某个返回值)。所以仅能被作为占位符使用,不能单独作为标识符使用。

// 定义的变量和包如果没有使用,编译会报错
// 不支持单行{}
// fun{
//  body
// }

// 起名规则
// (1)包名: 尽量保持 package 的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,和标准库不要冲突
// 1.为什么之前在定义源文件的时候,一般我们都用 package main 包?
// main 包是一个程序的入口包,所以你 main 函数它所在的包建议定义为 main 包,如果不定义为 main 包,那么就不能得到可执行文件。
// 2.尽量保持 package 的名字和目录保持一致
// (2)变量名、函数名、常量名 : 采用驼峰法。
// 就是单词按照大写区分开
// var stuNameDetail string = 'lili'
// (3)如果变量名、函数名、常量名首字母大写,则可以被其他的包访问;
// 如果首字母小写,则只能在本包中使用  (利用首字母大写小写完成权限控制)

变量

Go
// 全局变量的声明 --> 全局变量可以声明不使用,不会报错
// 1.一个一个声明
var glo1 int
var glo2 int
// 2.一次声明多个 --> var(变量声明)
var(
    glo3 int
    glo4 int
)
func main() {
    // 1.变量--> var 名字 类型
    // 2.变量不能重复声明
    var str string = "hello world"
    println(str)
    // 3.如果变量不初始化,则默认值为 0/空/false
    var age int
    var str1 string
    println("age =", age)
    println("str1 =", str1)
    // 4.变量声明如果不写类型,则会自动判断类型
    var str2 = "haihaihai"
    println(str2)
    // 5.一次声明多个变量
    var n1, n2, n3 int = 10, 20, 30
    println(n1, n2, n3)
    var m1, m2, m3 = 1, "haha", 3
    println(m1, m2, m3)
}

数据类型

基本数据类型

Go
// 数据类型--> 基本数据类型和复杂数据类型
    // 基本数据类型
    // 整形 -->
    // 有符号:int8,int16,int32,int64
    // 无符号:uint8,uint16.uint32,uint64
    // 其他整数类型--> byte==uint8 rune==int32
    // 浮点型 -->
    // float32, float64
    // 浮点数可以用 10 进制表示,也可用科学计数法表示
    // float64 精度更大,推荐使用 float64
    var ch1 byte = 'a'
    println(ch1)  // 打印出的是 ASCII 码
    // 字符是按 ASCII 码存储
    var ch2 int = '中'
    // 汉字为 Unicode 编码存储,故不能用 byte
    println(ch2)
    fmt.Printf("ch1 =%c\n", ch1)  // 格式化输出
    // bool 类型 --> true/false
    // 字符串类型 --> 不可变序列(指不能改变序列中单个字符)
    var s2 string = "abc"
    // s2 [0] ='e'  // 会报错
    s2 = "efg"  // 不会报错
    fmt.Println("s2 =", s2)
    // 字符串的表示形式--> 双引号和反引号
    // 1.没有特殊符号--> 双引号
    // 2.有特殊符号--> 反引号
    var s3 string = `
    abdakdcba)&U*&
        acbuaibcxaicsxa
        |||||||||||
        cxacxbakjcx`
    fmt.Println(s3)
    // 字符串的拼接 --> +
    fmt.Println(s2 + s3)

    // 基本数据类型转换 --> go 只有显式转换
    // 向上转换不会报错,但会发生数据截断
    // 运算时,最终结果类型以参与运算的数据类型最大的为主
    var f float64 = 5.022
    var fi int64 = int64(f)
    fmt.Println(fi)

    // 基本数据类型与字符串相互转换
    // 基本数据类型 --> string
    // 1.fmt.Sprintf 方法 --> 更常见
    var i1 int = 18
    var str3 string = fmt.Sprintf("%d", i1)  // 前面是要转化的数据格式化
    fmt.Printf("%T, str3 =%q\n", str3, str3)  // %T 为输出数据类型
    // 2.strconv 包方法
    var str4 string = strconv.FormatInt(int64(i1), 10)
    fmt.Printf("%T, str4 =%q\n", str4, str4)
    // string --> 基本数据类型
    //string --> bool
    var s1 string = "true"
    var b bool
    // ParseBool 这个函数的返回值有两个:(value bool, err error)
    // value 就是我们得到的布尔类型的数据,err 出现的错误
    // 我们只关注得到的布尔类型的数据,err 可以用_直接忽略
    b , _ = strconv.ParseBool(s1)
    fmt.Printf("b 的类型是:%T, b =%v \n", b, b)
    // string --> int64
    var s2 string = "19"
    var num1 int64
    num1,_ = strconv.ParseInt(s2,10,64)
    fmt.Printf("num1 的类型是:%T, num1 =%v \n", num1, num1)
    // string --> float32/float64
    var s3 string = "3.14"
    var f1 float64
    f1,_ = strconv.ParseFloat(s3,64)
    fmt.Printf("f1 的类型是:%T, f1 =%v \n", f1, f1)
    // 注意:string 向基本数据类型转换的时候,一定要确保 string 类型能够转成有效的数据类型,否则最后得到的结果就是按照对应类型的默认值输出

复杂数据类型

Go
// 复杂数据类型
    // 指针
    // 指针的声明
    var ptr *int = &i1
    fmt.Println(ptr)  //输出 i1 地址
    fmt.Println(*ptr)  //输出 ptr 对应地址的值

获取用户输入

Go
// 获取用户输入
    // 1.scanln
    fmt.Println("please input name:")
    var name string
    fmt.Scanln(&name)  //传入一个地址
    fmt.Println("your name is ", name)
    // 2.scanf
    fmt.Println("please input your id:")
    var id int
    fmt.Scanf("%d", &id)
    fmt.Println("your id is ", id)

分支结构

if-else if-else

Go
// 分支结构
    // if else(if else if else)
    var num int = 10
    if num > 100{
        fmt.Println("num > 100")
    }else{
        // else 不能另起一行
        fmt.Println(" num <= 100 ")
    }

    if num < 20 && num > 10{
        fmt.Println("num < 20 && num > 10")
    }else if num > 0 && num < 10{
        fmt.Println(" num > 0 && num < 10 ")
    }else{
        fmt.Println("num")
    }

switch

Go
switch
    // 给出一个学生分数:
    var score int = 187
    // 根据分数判断等级:
    // switch 后面是一个表达式,这个表达式的结果依次跟 case 进行比较,满足结果的话就执行冒号后面的代码。
    // default 是用来“兜底”的一个分支,其它 case 分支都不走的情况下就会走 default 分支
    // default 分支可以放在任意位置上,不一定非要放在最后。
    // 不用像 java 一样每个分支后面都加入 break 关键字
    switch score/10 {
            case 10 :
                    fmt.Println("您的等级为 A 级")
            case 9 :
                    fmt.Println("您的等级为 A 级")
            case 8 :
                    fmt.Println("您的等级为 B 级")
            case 7 :
                    fmt.Println("您的等级为 C 级")
            case 6 :
                    fmt.Println("您的等级为 D 级")
            case 5 :
                    fmt.Println("您的等级为 E 级")
            case 4 :
                    fmt.Println("您的等级为 E 级")
            case 3 :
                    fmt.Println("您的等级为 E 级")
            case 2 :
                    fmt.Println("您的等级为 E 级")
            case 1 :
                    fmt.Println("您的等级为 E 级")
            case 0 :
                    fmt.Println("您的等级为 E 级")
            default:
                    fmt.Println("您的成绩有误")
    }

循环结构

Go
// 循环结构
    1.普通 for 循环
    // 实现一个功能:求和: 1+2+3+4+5:
    // 求和:
    // 利用 for 循环来解决问题:
    var sum int = 0
    for i := 1; i <= 5; i++ {
        sum += i
    }

    // 输出结果:
    fmt.Println(sum)
    // for 循环的语法格式:
    // for 初始表达式; 布尔表达式(条件判断); 迭代因子 {
    //  循环体;--> 反复重复执行的内容
    // }
    // 注意:for 的初始表达式 不能用 var 定义变量的形式,要用:=
    // for range
    // 定义一个字符串:
    var str string = "hello golang 你好"
    // for range
    for i , value := range str {
            fmt.Printf("索引为:%d, 具体的值为:%c \n", i, value)
    }
    // 对 str 进行遍历,遍历的每个结果的索引值被 i 接收,每个结果的具体数值被 value 接收
    // 遍历对字符进行遍历的

函数

Go
// 函数
// func 函数名(形参列表)(返回值类型列表){
//  执行语句..
//  return + 返回值列表
// }
// 自定义函数:功能:两个数相加:
func cal (num1 int, num2 int) (int) {  //如果返回值类型就一个的话,那么()是可以省略不写的
    var sum int = 0
    sum += num1
    sum += num2
    return sum
}
// 基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。
// 以值传递方式的数据类型,如果希望在函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。从效果来看类似引用传递。
// 可变参数
// 定义一个函数,函数的参数为:可变参数 ...  参数的数量可变
// args...int 可以传入任意多个数量的 int 类型的数据  传入 0 个,1 个,,,,n 个
func test (args...int)(){
    // 函数内部处理可变参数的时候,将可变参数当做切片来处理
    // 遍历可变参数:
    for i := 0; i < len(args); i++ {
            fmt.Println(args [i])
    }
}
// 在 Go 中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用。
func testvar(num int)(){
    fmt.Println("testvar func", num)
}
// 函数作为形参
// 定义一个函数,把另一个函数作为形参:
func test02 (num1 int , num2 float32, testFunc func(int)){
    fmt.Println("-----test02")
}
// init 函数:初始化函数,可以用来进行一些初始化的操作
// 每一个源文件都可以包含一个 init 函数,该函数会在 main 函数执行前,被 Go 运行框架调用。
func init(){
    fmt.Println("this is init func")
}

    var a = testvar
    fmt.Printf("the type is %T\n", a)  //打印 a 的类型--> func(int)
    a(10)  //调用函数
    fmt.Printf("the feibonacc result is %d\n", publicfunc.Feibonacc(10))
    // chufa(10,0)
    ChufaTest(10,0)

错误捕获机制

Go
// defer 关键字
// defer 关键字的作用:
// 在函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时的释放资源,Go 的设计者提供 defer 关键字
// 程序在碰到 defer 关键字后不会立即执行后面的语句,而是会把语句推入一个栈中,继续执行之后的代码
// defer 语句执行顺序:按照栈的特点--> 先进后出
// 注:defer 将语句压入栈也会将相关的值同时拷贝入栈中,不会随着函数后面的变化而变化。

// 错误捕获机制 --> defer+recover: defer 加上匿名函数使用
func chufa(a int, b int)(int){
    defer func(){
        // recover 函数捕获错误--> 没有捕获到错误会返回 nil
        var err = recover()
        if err!= nil{
            fmt.Println("err is ", err)
        }
    }()
    return a/b
}

// 自定义错误
func ChufaTest(a int, b int)(int){
    if b==0{
        var err = errors.New("除数不能为 0")
        // errors.New()自定义错误
        fmt.Println("the error is ", err)
        return 0
    }else{
        return a/b
    }
}

数组

Go
// 数组:
    // 实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
    // 给出五个学生的成绩:---> 数组存储:
    // 1.定义一个数组:
    var scores [5] int
    // 2.数组的初始化
    // 第一种:
    var arr1 [3] int = [3] int{3,6,9}
    fmt.Println(arr1)
    // 第二种:
    var arr2 = [3] int{1,4,7}
    fmt.Println(arr2)
    // 第三种:
    var arr3 = [...] int{4,5,6,7}
    fmt.Println(arr3)
    // 第四种:
    var arr4 = [...] int{2: 66,0: 33,1: 99,3: 88}
    fmt.Println(arr4)
    // 3.数组的赋值与读取
    // 将成绩存入数组:(循环 + 终端输入)
    for i := 0; i < len(scores); i++ {  //i:数组的下标
        fmt.Printf("请录入第个%d 学生的成绩", i + 1)
        fmt.Scanln(&scores [i])
    }
    // 展示一下班级的每个学生的成绩:(数组进行遍历)
    // 方式 1:普通 for 循环:
    for i := 0; i < len(scores); i++ {
            fmt.Printf("第%d 个学生的成绩为:%d\n", i+1, scores [i])
    }
    fmt.Println("-------------------------------")
    // 方式 2:for-range 循环
    for key, value := range scores {
            fmt.Printf("第%d 个学生的成绩为:%d\n", key + 1, value)
    }
    // 5.Go 中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。
    // 如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。
    // 二维数组
    // 定义二维数组:
    var arr [3][3] int = [3][3] int{{1,4,7},{2,5,8},{3,6,9}}
    fmt.Println(arr)
    fmt.Println("------------------------")
    // 方式 1:普通 for 循环:
    for i := 0; i < len(arr); i++{
            for j := 0; j < len(arr[i]); j++ {
                    fmt.Print(arr [i][j], "\t")
            }
            fmt.Println()
    }
    fmt.Println("------------------------")
    // 方式 2:for range 循环:
    for key, value := range arr {
            for k, v := range value {
                    fmt.Printf("arr [%v][%v] =%v\t", key, k, v)
            }
            fmt.Println()
    }

切片

Go
// 切片--> 和 python 类似
    // 定义数组: 
    var intarr [6] int = [6] int{3,6,9,1,4,7}
    // 切片构建在数组之上:
    // 定义一个切片名字为 slice,[]动态变化的数组长度不写,int 类型,intarr 是原数组
    // [ 1:3 ]切片 —切出的一段片段 —索引:从 1 开始,到 3 结束(不包含 3)—[ 1,3)
    // 切片初始化方式
    // 1.数组截取
    // var slice [] int = intarr [1: 3]
    slice := intarr [1: 3]
    // 输出数组:
    fmt.Println("'intarr:", intarr)
    // 输出切片: 
    fmt.Println("slice:", slice)
    // 2.make 函数
    // 定义切片:make 函数的三个参数:1 .切片类型 2 .切片长度 3 .切片的容量 slice := make([] int,4,20)
    // fmt.Print1n(slice)///[0 0 0 0] 
    fmt.Println("切片的长度:", len(slice))
    fmt.Println("切片的容量:", cap(slice)) 
    slice [0] = 66
    slice [1] = 88 
    fmt.Println(slice) 
    // 切片的动态增长--> 也可追加切片
    fmt.Println(len(slice))
    slice2 := append(slice,88,50)
    fmt.Println(slice2) //[4 7 3 88 50]
    fmt.Println(slice)
    // 底层原理:
    // 1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
    // 2.创建一个新数组,将老数组中的 4,7,3 复制到新数组中,在新数组中追加 88,50
    // 3.slice2 底层数组的指向 指向的是新数组 
    // 4.往往我们在使用追加的时候其实想要做的效果给 slice 追加:
    slice = append(slice,88,50)
    fmt.Println(slice)
    // 5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
    // 切片的拷贝
    // 定义切片:
    var a [] int = [] int{1,4,7,3,6,9}
    // 再定义一个切片:
    var b [] int = make([] int,10)
    // 拷贝:
    copy(b, a) //将 a 中对应数组中元素内容复制到 b 中对应的数组中
    fmt.Println(b)