Golang基础教程

时间:2024-10-10 10:12:00

第一章:走进Golang

Golang引入

  • 简介: Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种计算机编程语言语言。
  • 设计初衷: Go语言是谷歌推出的一种的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发Go,是因为过去10多年间软件开发的难度令人沮丧。派克表示,和今天的C++或C一样,Go是一种系统语言。他解释道,"使用它可以进行快速开发,同时它还是一个真正的编译语言,我们之所以现在将其开源,原因是我们认为它已经非常有用和强大。"
  1. 计算机硬件技术更新频繁,性能提高很快。目前主流的编程语言发展明显落后于硬件,不能合理利用多核多CPU的优势提升软件系统性能。
  2. 软件系统复杂度越来越高,维护成本越来越高,目前缺乏一个足够简洁高效的编程语言。
  3. 企业运行维护很多c/c++的项目,c/c++程序运行速度虽然很快,但是编译速度确很慢,同时还存在内存泄漏的一系列的困扰需要解决。
  • 应用领域:

第一段程序:Hello Golang!

  • go基本目录结构:

  • 开始写代码:第一个HelloWorld :
  1. package main //声明文件所在的包,每个go文件必须有归属的包
  2. import "fmt" //引入程序中需要用的包,为了使用包下的函数 比如:Println
  3. func main () { //main 主函数 程序的入口
  4. ("Hello Golang!!") //在控制台打印输出一句话,Hello Golang!!
  5. }
  6. 复制代码
  • 对源文件进行编译:go bulid

  • 执行操作

  • 也可以通过go run直接编译、执行文件(但不生成exe文件)

Golang执行流程

  • 执行流程分析:

  • 上述两种执行流程的方式区别

    1. 在编译时,编译器会将程序运行依赖的库文件包含在可执行文件中,所以,可执行文件 变大了很多。

    2. 如果我们先编译生成了可执行文件,那么我们可以将该可执行文件拷贝到没有go开发环境的机器上,仍然可以运行
    3. 如果我们是直接go run go源代码,那么如果要在另外一个机器上这么运行,也需要go 开发环境,否则无法执行。
    4. go run运行时间明显要比第一种方式 长一点点
  • 编译注意事项: 编译后的文件可以另外指定名字:

语法注意事项

  • 源文件以"go"为扩展名。
  • 程序的执行入口是main()函数。
  • 严格区分大小写。
  • 方法由一条条语句构成,每个语句后不需要分号(Go语言会在每行后自动加分号),这也体现出Golang的简洁性。
  • Go编译器是一行行进行编译的,因此我们一行就写一条语句,不能把多条语句写在同一个,否则报错
  • 定义的变量或者import的包如果没有使用到,代码不能编译通过。
  • 大括号都是成对出现的,缺一不可

注释

  • 注释的作用: 用于注解说明解释程序的文字就是注释,注释提高了代码的阅读性; 注释是一个程序员必须要具有的良好编程习惯。 将自己的思想通过注释先整理出来,再用代码去体现。

  • Golang中注释类型: Go支持c语言风格的/**/块注释,也支持c++风格的//行注释。行注释更通用,块注释主要用于针对包的详细说明或者屏蔽大块的代码

    • 行注释 // VSCode快捷键:ctrl+/ 再按一次取消注释

    • 块注释(多行注释) /**/ VSCode快捷键:shift+alt+a 再按一次取消注释

      注意:块注释中不可以嵌套块注释

提示:官方推荐使用行注释 //

代码风格

  • 注意缩进

    向后缩进:tab 向前取消缩进:shift+tab 通过命令完成格式化操作:

  • 成对编程 {} () “ ” ‘ ’
  • 运算符两边加空白 ( ps : 一般来说,写代码的时候都得这样,这是规范编写代码的好习惯 )
  • 以下代码是错误的:

go的设计者想要开发者有统一的代码风格

  • 行长约定:

    一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅

API

Go语言提供了大量的标准库,因此 google 公司也为这些标准库提供了相应的API文档,用于告诉开发者如何使用这些标准库,以及标准库包含的方法。

  • 官方文档
  • Golang中文网在线标准库文档
  • 当然也可以自己下载离线文档:Go参考手册下载,Go离线CHM手册下载,Go中文手册下载-爱测速网 ()

第二章 变量与数据类型

变量

  • 简单代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //1.变量的声明
  5.    var age int
  6.    //2.变量的赋值
  7.    age = 18
  8.    //3.变量的使用
  9.    ("age = ", age);
  10.    //声明和赋值可以合成一句:
  11.    var age2 int = 19
  12.    ("age2 = ", age2);
  13.    // var age int = 20;
  14.    // ("age = ", age);
  15.    /*变量的重复定义会报错:
  16.         # command-line-arguments
  17.         .\main.go:16:6: age redeclared in this block
  18.                        previous declaration at .\main.go:6:6
  19.        */
  20.    //不可以在赋值的时候给与不匹配的类型
  21.    var num int = 12.56 //报错
  22.    ("num = ", num);
  23. }
  24. 复制代码
  • 变量的四种定义方法、一次性声明多个变量(代码展示)
  1. package main
  2. import "fmt"
  3. //全局变量:定义在函数外的变量
  4. var n7 = 100
  5. var n8 = 9.7
  6. //设计者认为上面的全局变量的写法太麻烦了,可以一次性声明:
  7. var (
  8.    n9 = 500
  9.    n10 = "netty"
  10. )
  11. func main(){
  12.    //定义在{}中的变量叫:局部变量
  13.    //第一种:变量的使用方式:指定变量的类型,并且赋值,
  14.    var num int = 18
  15.    (num) //18
  16.    //第二种:指定变量的类型,但是不赋值,使用默认值
  17.    var num2 int
  18.    (num2) //0
  19.    //第三种:如果没有写变量的类型,那么根据=后面的值进行判定变量的类型 (自动类型推断)
  20.    var num3 = "tom"
  21.    (num3) //tom
  22.    //第四种:省略var,注意 := 不能写为 =  
  23.    sex := "男"
  24.    (sex) //
  25.    ("------------------------------------------------------------------")
  26.    //声明多个变量:
  27.    var n1,n2,n3 int
  28.    (n1) //0
  29.    (n2) //0
  30.    (n3) //0
  31.    var n4,name,n5 = 10,"jack",7.8
  32.    (n4) //10
  33.    (name) //jack
  34.    (n5) //7.8
  35.    n6,height := 6.9,100.6
  36.    (n6) //6.9
  37.    (height) //100.6
  38.    //全局变量输出
  39.    (n7) //100
  40.    (n8) //9.7
  41.    (n9) //500
  42.    (n10) //netty
  43. }
  44. 复制代码

基本数据类型

整数类型

  • 有符号整数类型

  • 无符号整数类型

  • 其他整数类型

Golang的整数类型,默认声明为int类型

Golang程序中整型变量在使用时,遵守保小不保大的原则,即:在保证程序正确运行下,尽量使用占用空间小的数据类型

浮点类型

  • 浮点类型种类

  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //定义浮点类型的数据:
  5.    var num1 float32 = 3.14
  6.    (num1)
  7.    //可以表示正浮点数,也可以表示负的浮点数
  8.    var num2 float32 = -3.14
  9.    (num2)
  10.    //浮点数可以用十进制表示形式,也可以用科学计数法表示形式 E 大写小写都可以的
  11.    var num3 float32 = 314E-2
  12.    (num3) //3.14
  13.    var num4 float32 = 314E+2
  14.    (num4) //31400
  15.    var num5 float32 = 314e-2
  16.    (num5) //3.14
  17.    var num6 float64 = 314e+2
  18.    (num6) //31400
  19.    //浮点数可能会有精度的损失,所以通常情况下,建议你使用:float64
  20.    var num7 float32 = 256.000000916
  21.    (num7) //256
  22.    var num8 float64 = 256.000000916
  23.    (num8) //256.000000916
  24.    //golang中默认的浮点类型为:float64
  25.    var num9 = 3.17
  26.    ("num9对应的默认的类型为:%T", num9) //num9对应的默认的类型为:float64
  27. }
  28. 复制代码

字符类型

  • Golang中没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存。
  • Golang中字符使用UTF-8编码
  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //定义字符类型的数据:
  5.    var c1 byte = 'a'
  6.    (c1)//97
  7.    var c2 byte = '6'
  8.    (c2)//54
  9.    var c3 byte = '('
  10.    (c3 + 20)//40
  11.    //字符类型,本质上就是一个整数,也可以直接参与运算,输出字符的时候,会将对应的码值做一个输出
  12.    //字母,数字,标点等字符,底层是按照ASCII进行存储。
  13.    var c4 int = '中'
  14.    (c4) //20013
  15.    //汉字字符,底层对应的是Unicode码值
  16.    //对应的码值为20013,byte类型溢出,能存储的范围:可以用int
  17.    //总结:Golang的字符对应的使用的是UTF-8编码(Unicode是对应的字符集,UTF-8是Unicode的其中的一种编码方案)
  18.    var c5 byte = 'A'
  19.    //想显示对应的字符,必须采用格式化输出
  20.    ("c5对应的具体的字符为:%c", c5) //c5对应的具体的字符为:A
  21. }
  22. 复制代码

布尔类型

  • 布尔类型也叫bool类型,bool类型数据只允许取值true和false
  • 布尔类型占1个字节
  • 布尔类型适于逻辑运算,一般用于程序流程控制
  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //测试布尔类型的数值:
  5.    var flag01 bool = true
  6.    (flag01) //true
  7.    var flag02 bool = false
  8.    (flag02) //false
  9.    var flag03 bool = 5 < 9
  10.    (flag03) //true
  11. }
  12. 复制代码

字符串类型

  • 字符串就是一串固定长度的字符连接起来的字符序列
  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //1.定义一个字符串:
  5.    var s1 string = "你好全面拥抱Golang"
  6.    (s1)
  7.    //2.字符串是不可变的:指的是字符串一旦定义好,其中的字符的值不能改变
  8.    var s2 string = "abc"
  9.    
  10.    (s2)
  11.    //3.字符串的表示形式:
  12.    //1)如果字符串中没有特殊字符,字符串的表示形式用双引号
  13.    //var s3 string = "asdfasdfasdf"
  14.    //2)如果字符串中有特殊字符,字符串的表示形式用反引号 ``
  15.    var s4 string = `
  16.        package main
  17.        import "fmt"
  18.        func main(){
  19.                //测试布尔类型的数值:
  20.                var flag01 bool = true
  21.                (flag01)
  22.                var flag02 bool = false
  23.                (flag02)
  24.                var flag03 bool = 5 < 9
  25.                (flag03)
  26.        }
  27.        `
  28.    (s4)
  29.    //4.字符串的拼接效果:
  30.    var s5 string = "abc" + "def"
  31.    s5 += "hijk"
  32.    (s5) //abcdefhijk
  33.    //当一个字符串过长的时候:注意:+保留在上一行的最后
  34.    var s6 string = "abc" + "def" + "abc" + "def" + "abc" + "def" + "abc" +
  35.    "def"+ "abc" + "def" + "abc" + "def"+ "abc" + "def" + "abc" + "def"+
  36.    "abc" + "def" + "abc" + "def"+ "abc" + "def" + "abc" + "def"+ "abc" +
  37.    "def" + "abc" + "def"+ "abc" + "def" + "abc" + "def"+ "abc" + "def" +
  38.    "abc" + "def"+ "abc" + "def"
  39.    (s6) //......
  40. }
  41. 复制代码

基本数据类型的默认值

  • 在Golang中数据类型都有一个默认值,当程序员没有赋值时,就会保留默认值(默认值又叫零值)

基本数据类型之间的转换

  • Go在不同类型的变量之间赋值时需要显式转换,并且只有显式转换(强制转换)
  • 语法:T(v) 将值v转换为类型T。T : 就是数据类型,v : 就是需要转换的变量
  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //进行类型转换:
  5.    var n1 int = 100
  6.    //var n2 float32 = n1 在这里自动转换不好使,比如显式转换
  7.    (n1)
  8.    //(n2)
  9.    var n2 float32 = float32(n1)
  10.    (n2)
  11.    //注意:n1的类型其实还是int类型,只是将n1的值100转为了float32而已,n1还是int的类型
  12.    ("%T", n1)  //int
  13.    ()
  14.    //将int64转为int8的时候,编译不会出错的,但是会数据的溢出
  15.    var n3 int64 = 888888
  16.    var n4 int8 = int8(n3)
  17.    (n4)//56
  18.    var n5 int32 = 12
  19.    var n6 int64 = int64(n5) + 30  //一定要匹配=左右的数据类型
  20.    (n5)
  21.    (n6)
  22.    var n7 int64 = 12
  23.    var n8 int8 = int8(n7) + 127  //编译通过,但是结果可能会溢出
  24.    //var n9 int8 = int8(n7) + 128 //编译不会通过
  25.    (n8)
  26.    //(n9)
  27. }
  28. 复制代码

基本数据类型转为string

  • 基本数据类型和string的转换介绍在程序开发中,我们经常需要将基本数据类型转成string类型。或者将string类型转成基本数据类型
  • 方法

    方式1:("%参数",表达式) ---> 重点练习这个,推荐方式 方式2:使用strconv包的函数

  • 代码展示

  1. package main
  2. import "fmt"
  3. func main(){
  4.    var n1 int = 19
  5.    var n2 float32 = 4.78
  6.    var n3 bool = false
  7.    var n4 byte = 'a'
  8.    var s1 string = ("%d",n1)
  9.    ("s1对应的类型是:%T ,s1 = %q \n",s1, s1)//s1对应的类型是:string ,s1 = "19"
  10.    var s2 string = ("%f",n2)
  11.    ("s2对应的类型是:%T ,s2 = %q \n",s2, s2) //s2对应的类型是:string ,s2 = "4.780000"
  12.    var s3 string = ("%t",n3)
  13.    ("s3对应的类型是:%T ,s3 = %q \n",s3, s3) //s3对应的类型是:string ,s3 = "false"
  14.    var s4 string = ("%c",n4) //s4对应的类型是:string ,s4 = "a"
  15.    ("s4对应的类型是:%T ,s4 = %q \n",s4, s4)
  16. }
  17. 复制代码
  1. package main
  2. import(
  3.    "fmt"
  4.    "strconv"
  5. )
  6. func main(){
  7.    var n1 int = 18
  8.    var s1 string = (int64(n1),10)  //参数:第一个参数必须转为int64类型 ,第二个参数指定字面值的进制形式为十进制
  9.    ("s1对应的类型是:%T ,s1 = %q \n",s1, s1)
  10.    var n2 float64 = 4.29
  11.    var s2 string = (n2,'f',9,64)
  12.    //第二个参数:'f'(-) 第三个参数:9 保留小数点后面9位 第四个参数:表示这个小数是float64类型
  13.    ("s2对应的类型是:%T ,s2 = %q \n",s2, s2)
  14.    var n3 bool = true
  15.    var s3 string = (n3)
  16.    ("s3对应的类型是:%T ,s3 = %q \n",s3, s3)
  17. }
  18. 复制代码

string转为基本数据类型

  • 使用strconv包的函数
  • 代码展示
  1. package main
  2. import(
  3.    "fmt"
  4.    "strconv"
  5. )
  6. func main(){
  7.    //string-->bool
  8.    var s1 string = "true"
  9.    var b bool
  10.    //ParseBool这个函数的返回值有两个:(value bool, err error)
  11.    //value就是我们得到的布尔类型的数据,err出现的错误
  12.    //我们只关注得到的布尔类型的数据,err可以用_直接忽略
  13.    b , _ = (s1)
  14.    ("b的类型是:%T,b=%v \n", b, b)
  15.    //string-->int64
  16.    var s2 string = "19"
  17.    var num1 int64
  18.    num1,_ = (s2,10,64)
  19.    ("num1的类型是:%T,num1=%v \n", num1, num1)
  20.    //string-->float32/float64
  21.    var s3 string = "3.14"
  22.    var f1 float64
  23.    f1,_ = (s3, 64)
  24.    ("f1的类型是:%T,f1=%v \n", f1, f1)
  25.    //注意:string向基本数据类型转换的时候,一定要确保string类型能够转成有效的数据类型,否则最后得到的结果就是按照对应类型的默认值输出
  26.    var s4 string = "golang"
  27.    var b1 bool
  28.    b1 , _ = (s4)
  29.    ("b1的类型是:%T,b1=%v \n", b1, b1)
  30.    var s5 string = "golang"
  31.    var num2 int64
  32.    num2, _ = (s5, 10, 64)
  33.    ("num2的类型是:%T,num2=%v \n", num2, num2)
  34. }
  35. 复制代码

复杂数据类型

指针

  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    var age int = 18
  5.    //&符号+变量 就可以获取这个变量内存的地址
  6.    (&age) //0xc0000a2058
  7. }
  8. 复制代码

  1. package main
  2. import "fmt"
  3. func main(){
  4.    var age int = 18
  5.    //&符号+变量 就可以获取这个变量内存的地址
  6.    (&age) //0xc0000a2058
  7.    //定义一个指针变量:
  8.    //var代表要声明一个变量
  9.    //ptr 指针变量的名字
  10.    //ptr对应的类型是:*int 是一个指针类型 (可以理解为 指向int类型的指针)
  11.    //&age就是一个地址,是ptr变量的具体的值
  12.    var ptr *int = &age
  13.    (ptr)
  14.    ("ptr本身这个存储空间的地址为:", &ptr)
  15.    //想获取ptr这个指针或者这个地址指向的那个数据:
  16.    ("ptr指向的数值为:%v", *ptr) //ptr指向的数值为:18
  17. }
  18. 复制代码

标识符的使用

  • 什么是标识符

    • 变量,方法等,只要是起名字的地方,那个名字就是标识符 如:
  1. var age int = 19 // age
  2. var price float64 = 9.8 // price
  3. 复制代码
  • 标识符定义规则

    • 三个可以(组成部分):数字,字母,下划线_
    • 四个注意:不可以以数字开头,严格区分大小写,不能包含空格,不可以使用Go中的保留关键字
    • 见名知意:增加可读性
    • 下划线"_"本身在Go中是一个特殊的标识符,称为空标识符。可以代表任何其它的标识符,但是它对应的值会被忽略(比如:忽略某个返回值)。所以仅能被作为占位符使用,不能单独作为标识符使用
    • 长度不限制,但是不建议名字太长
    • 变量名、函数名、常量名 : 采用驼峰命名法
    • 如果变量名、函数名、常量名首字母大写,则可以被其他的包访问。如果首字母小写,则只能在本包中使用 (利用首字母大写小写完成权限控制)

关键字和预定义标识符

  • 关键字就是程序发明者规定的有特殊含义的单词,又叫保留字。go语言中一共有25个关键字

  • 预定义标识符:一共36个预定标识符,包含基础数据类型和系统内嵌函数

第三章:运算符

  • 运算符这一块就不过多赘述了,简单展示go语言的语法特点
  • 代码展示
  1. var a int = 10
  2. a++
  3. (a)
  4. a--
  5. (a)
  6. //++ 自增 加1操作,--自减,减1操作
  7. //go语言里,++,--操作非常简单,只能单独使用,不能参与到运算中去
  8. //go语言里,++,--只能在变量的后面,不能写在变量的前面 --a ++a 错误写法
  9. 复制代码

第四章:流程控制

分支结构

  • if分支,代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    if score >= 90 {
  5.   ("您的成绩为A级别")
  6.   } else if score >= 80 {//else隐藏:score < 90
  7.   ("您的成绩为B级别")
  8.   } else if score >= 70 {//score < 80
  9.   ("您的成绩为C级别")
  10.   } else if score >= 60 {//score < 70
  11.   ("您的成绩为D级别")
  12.   } else {//score < 60
  13.   ("您的成绩为E级别")
  14.   } //建议你保证else的存在,只有有了else才会真正 起到多选一 的效果
  15. }
  16. 复制代码
  • switch分支,代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //给出一个学生分数:
  5.    var score int = 87
  6.    //根据分数判断等级:
  7.    //switch后面是一个表达式,这个表达式的结果依次跟case进行比较,满足结果的话就执行冒号后面的代码。
  8.    //default是用来“兜底”的一个分支,其它case分支都不走的情况下就会走default分支
  9.    //default分支可以放在任意位置上,不一定非要放在最后。
  10.    switch score/10 {
  11.        case 10 :
  12.                ("您的等级为A级")
  13.        case 9 :
  14.                ("您的等级为A级")
  15.        case 8 :
  16.                ("您的等级为B级")
  17.        case 7 :
  18.                ("您的等级为C级")
  19.        case 6 :
  20.                ("您的等级为D级")
  21.        case 5 :
  22.                ("您的等级为E级")
  23.        default:
  24.                ("您的成绩有误")
  25.   }
  26. }
  27. 复制代码
  • 注意事项

    • switch后是一个表达式(即:常量值、变量、一个有返回值的函数等都可以)
    • case后面的值如果是常量值(字面量),则要求不能重复
    • case后的各个值的数据类型,必须和 switch 的表达式数据类型一致
    • case后面可以带多个值,使用逗号间隔。比如 case 值1,值2...
    • case后面不需要带break
    • default语句不是必须的,位置也是随意的。
    • switch后也可以不带表达式,当做if分支来使用
    • switch后也可以直接声明/定义一个变量,分号结束,不推荐
    • switch穿透,利用fallthrough关键字,如果在case语句块后增加fallthrough ,则会继续执行下一个case,也叫switch穿透。

循环结构

  • for循环
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //实现一个功能:求和: 1+2+3+4+5
  5.    //求和:
  6.    //利用for循环来解决问题:
  7.    var sum int = 0
  8.    for i := 1; i <= 5; i++ {
  9.        sum += i
  10.   }
  11.    
  12.    //输出结果:
  13.    (sum) //15
  14.    // for循环的语法格式:
  15.    // for 初始表达式; 布尔表达式(条件判断); 迭代因子 {
  16.    // 循环体;-->反复重复执行的内容
  17.    // }
  18.    // 注意:for的初始表达式 不能用var定义变量的形式,要用:=
  19. }
  20. 复制代码
  • for range
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //定义一个字符串:
  5.    var str string = "hello golang你好"
  6.    for i, value := range str {
  7.        ("索引为:%d,具体的值为:%c \n", i, value)
  8.   }
  9.    //对str进行遍历,遍历的每个结果的索引值被i接收,每个结果的具体数值被value接收
  10.    //遍历对字符进行遍历的
  11. }
  12. 复制代码

第五章:函数

函数细节详解

  • 基本语法
  1. func 函数名 (形参列表) (返回值类型列表) {
  2.    执行语句..
  3.    return + 返回值列表
  4. }
  5. 复制代码
  • 返回值,特点就是go语言可以返回多个参数
  1. package main
  2. import "fmt"
  3. func cal (num1 int, num2 int) (int, int) {
  4.    var sum int = num1 + num2
  5.    var sub int = num1 - num2
  6.    return sum, sub
  7. }
  8. func main(){
  9.    sum, sub := cal(66, 33)
  10.    //也可以用下划线忽略
  11.    sum1, _ := cal(11, 22)
  12.    (sum, sub) //99, 33
  13.    (sum1) //33
  14. }
  15. 复制代码

包的细节详解

  • package进行包的声明,建议:包的声明这个包和所在的文件夹同名
  • main包是程序的入口包,一般main函数会放在这个包下。main函数一定要放在main包下,否则不能编译执行
  • 打包语法:
  1. package 包名
  2. 复制代码
  • 引入包的语法:import "包的路径"。包名是从$GOPATH/src/后开始计算的,使用/进行路径分隔。(配置完变量一定要重启IDE,不然编辑器还没反应过来。我被这个坑了好一段时间)

  • 如果有多个包,建议一次性导入,格式如下:
  1. import(
  2.    "fmt"
  3.    "gocode/testproject01/unit5/demo09/crm/dbutils"
  4. )
  5. 复制代码
  • 在函数调用的时候前面要定位到所在的包
  • 函数名,变量名首字母大写,函数,变量可以被其它包访问
  • 一个目录下不能有重复的函数
  • 包名和文件夹的名字,可以不一样
  • 一个目录下的同级文件归属一个包
  • 同级别的源文件的包的声明必须一致
  • 可以给包取别名,取别名后,原来的包名就不能使用了

  • 包到底是什么:

    • 在程序层面,所有使用相同 package 包名 的源文件组成的代码模块
    • 在源文件层面就是一个文件夹

init函数

  • init函数:初始化函数,可以用来进行一些初始化的操作 每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用
  • 全局变量定义,init函数,main函数的执行流程?
  1. package main
  2. import "fmt"
  3. var num int = test();
  4. func test() int {
  5.    ("test函数被调用执行")
  6.    return 10
  7. }
  8. func init() {
  9.    ("init函数被调用执行")
  10. }
  11. func main() {
  12.    ("main函数被调用执行")
  13. }
  14. 复制代码

输出结果:

  • 多个源文件都有init函数的时候,如何执行?

匿名函数

  • Go支持匿名函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数
  • 匿名函数使用方式:

在定义匿名函数时就直接调用,这种方式匿名函数只能调用一次(用的多)

  1. package main
  2. import "fmt"
  3. func main() {
  4.    //定义匿名函数,定义的同时调用
  5.    result := func (num1 int, num2 int) int {
  6.        return num1 + num2
  7.   } (10, 20) //直接输入参数
  8.    (result) //30
  9. }
  10. 复制代码

将匿名函数赋给一个变量(该变量就是函数变量了),再通过该变量来调用匿名函数(用的少)

  1. package main
  2. import "fmt"
  3. func main() {
  4.    //定义匿名函数,定义的同时调用
  5.    result := func (num1 int, num2 int) int {
  6.        return num1 + num2
  7.   }
  8.    result1 := result(10, 20) //调用result匿名函数
  9.    (result1) //30
  10. }
  11. 复制代码

如何让一个匿名函数,可以在整个程序中有效呢?将匿名函数给一个全局变量就可以了

  1. package main
  2. import "fmt"
  3. var add = func (num1 int, num2 int) int {
  4.    return num1 + num2
  5. }
  6. func main() {
  7.    result := add(10, 20) //调用add
  8.    (result) //30
  9. }
  10. 复制代码

闭包

  • 什么是闭包?

闭包就是一个函数和与其相关的引用环境组合的一个整体

  • 代码展示
  1. package main
  2. import "fmt"
  3. //函数功能:求和
  4. //函数的名字:getSum 参数为空
  5. //getSum函数返回值为一个函数,这个函数的参数是一个int类型的参数,返回值也是int类型
  6. func getSum() func (int) int {
  7.    var sum int = 0
  8.    return func (num int) int{
  9.        sum = sum + num
  10.        return sum
  11.   }
  12. }
  13. //闭包:返回的匿名函数+匿名函数以外的变量num
  14. func main(){
  15.    f := getSum()
  16.    (f(1))//1
  17.    (f(2))//3
  18.    (f(3))//6
  19.    (f(4))//10
  20. }
  21. 复制代码

匿名函数中引用的那个变量会一直保存在内存中,可以一直使用

  • 闭包的本质

    • 闭包本质依旧是一个匿名函数,只是这个函数引入外界的变量/参数
    • 匿名函数+引用的变量/参数 = 闭包
  • 特点

    • 返回的是一个匿名函数,但是这个匿名函数引用到函数外的变量/参数 ,因此这个匿名函数就和变量/参数形成一个整体,构成闭包。
    • 闭包中使用的变量/参数会一直保存在内存中,所以会一直使用--->意味着闭包不可滥用(对内存消耗大)

defer关键字

  • 作用

在函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer关键字

  • 代码展示
  1. package main
  2. import "fmt"
  3. var add = func (num1 int, num2 int) int {
  4.    //在Golang中,程序遇到defer关键字,
  5.    //不会立即执行defer后的语句,而是先将语句压入一个栈中,然后继续执行后面的语句
  6.    defer ("num1=", num1) //33
  7.    defer ("num2=", num2) //66
  8.    
  9.    sum := num1 + num2
  10.    ("sum=", sum) //99
  11.    return sum
  12. }
  13. func main() {
  14.    (add(33, 66)) //99
  15. }
  16. 复制代码

结果:

  • 应用场景

比如你想关闭某个使用的资源,在使用的时候直接随手defer,因为defer有延迟执行机制(函数执行完毕再执行defer压入栈的语句),所以你用完随手写了关闭,比较省心,省事

第六章:错误处理

defer+recover机制处理错误

  • 错误处理/捕获机制:

go中追求代码优雅,引入机制:defer+recover机制处理错误

内置函数recover:

  1. package main
  2. import "fmt"
  3. func main() {
  4.    test()
  5.    ("上面的语句执行成功")
  6. }
  7. func test() {
  8.    //利用defer+recover来捕获错误:defer后加上匿名函数的调用
  9.    defer func() {
  10.        //调用defer内置函数,可以捕获错误
  11.        err := recover();
  12.        //如果没有捕获错误,返回值为零值:nil
  13.        if err != nil {
  14.            ("错误已经捕获")
  15.            ("err是", err)
  16.       }
  17.   }()
  18.    num1 := 33
  19.    num2 := 66
  20.    result := num1 + num2
  21.    (result)
  22. }
  23. 复制代码

结果:

自定义错误

需要调用errors包下的New函数:函数返回error类型

  1. package main
  2. import (
  3.    "fmt"
  4.    "errors"
  5. )
  6. func main() {
  7.    err := test()
  8.    if err != nil {
  9.        ("自定义错误:", err)
  10.   }
  11.    ("上面的语句执行成功")
  12. }
  13. func test() (err error){
  14.    num1 := 10
  15.    num2 := 0
  16.    if num2 == 0 {
  17.        //抛出自定义错误:
  18.        return ("除数不能为零!!!")
  19.   } else {
  20.        result := num1 / num2
  21.        (result)
  22.        //如果没有错误,返回零值
  23.        return nil
  24.   }
  25. }
  26. 复制代码

结果

第七章:数组

数组的初始化方式

  1. package main
  2. import "fmt"
  3. func main(){
  4.    //第一种:
  5.    var arr1 [3]int = [3]int{3,6,9}
  6.    (arr1)
  7.    //第二种:
  8.    var arr2 = [3]int{1,4,7}
  9.    (arr2)
  10.    //第三种:
  11.    var arr3 = [...]int{4,5,6,7}
  12.    (arr3)
  13.    //第四种:定义对应下标
  14.    var arr4 = [...]int{2:66,0:33,1:99,3:88}
  15.    (arr4)
  16. }
  17. 复制代码

数组的遍历

  • 普通for循环
  • 键值循环

(键值循环)for range结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道,for range 语法上类似于其它语言中的 foreach 语句,一般形式为:

  1. for key, val := range coll {
  2.    ...
  3. }
  4. 复制代码

注意: (1)coll就是你要的数组 (2)每次遍历得到的索引用key接收,每次遍历得到的索引位置上的值用val (3)key、value的名字随便起名 k、v key、value (4)key、value属于在这个循环中的局部变量 (5)你想忽略某个值:用 _ 接收就可以了

  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //实现的功能:给出五个学生的成绩,求出成绩的总和,平均数:
  5.    //给出五个学生的成绩:--->数组存储:
  6.    //定义一个数组:
  7.    var scores [5]int
  8.    //将成绩存入数组:(循环 + 终端输入)
  9.    for i := 0; i < len(scores);i++ {//i:数组的下标
  10.        ("请录入第个%d学生的成绩",i + 1)
  11.        (&scores[i])
  12.   }
  13.    //展示一下班级的每个学生的成绩:(数组进行遍历)
  14.    //方式1:普通for循环:
  15.    for i := 0; i < len(scores);i++ {
  16.        ("第%d个学生的成绩为:%d\n",i+1,scores[i])
  17.   }
  18.    ("-------------------------------")
  19.    //方式2:for-range循环
  20.    for key,value := range scores {
  21.        ("第%d个学生的成绩为:%d\n",key + 1,value)
  22.   }
  23. }
  24. 复制代码

注意事项

  • 长度属于类型的一部分
  1. package main
  2. import "fmt"
  3. func main() {
  4.    var arr1 = [3]int{3, 6, 9}
  5.    ("数组的类型为:%T", arr1) //数组的类型为:[3]int
  6.    ()
  7.    var arr2 = [6]int{3, 6, 9, 2, 4, 6}
  8.    ("数组的类型为:%T", arr2) //数组的类型为:[6]int
  9. }
  10. 复制代码
  • Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝

  • 如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)。

第八章:切片

切片的引入

  • 切片(slice)是golang中一种特有的数据类型
  • 数组有特定的用处,但是却有一些呆板(数组长度固定不可变),所以在 Go 语言的代码里并不是特别常见。相对的切片却是随处可见的,切片是一种建立在数组类型之上的抽象,它构建在数组之上并且提供更强大的能力和便捷。
  • 切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。
  • 切片的语法:
  1. var 切片名 []类型 = 数组的一个片段引用
  2. 复制代码
  • 代码展示
  1. package main
  2. import "fmt"
  3. func main() {
  4.    //定义数组:
  5.    var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}
  6.    //切片构建在数组之上
  7.    slice := intarr[1 : 3]
  8.    //输出数组
  9.    ("intarr:", intarr)
  10.    //输出切片
  11.    ("slice:", slice)
  12.    //输出切片个数
  13.    ("slice的元素个数", len(slice))
  14.    //获取切片的容量:容量可以动态变化
  15.    ("slice的容量", cap(slice))
  16. }
  17. 复制代码

结果:

内存分析

切片是一个有三个字段的数据结构,这些数据结构包含 Golang 需要操作底层数组的元数据:

切片的定义

  1. //定义数组:
  2. var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}
  3. //切片构建在数组之上
  4. //方式1:定义一个切片,然后让切片去引用一个已经创建好的数组
  5. slice1 := intarr[1 : 3]
  6. //方式2:通过make内置函数来创建切片。基本语法: var切片名[type = make([], len,[cap])
  7. //PS : make底层创建一个数组,对外不可见,所以不可以直接操作这个数组,
  8. //要通过slice去间接的访问各个元素,不可以直接对数组进行维护/操作
  9. slice2 := make([]int , 4, 20)
  10. //方式3:定一个切片,直接就指定具体数组,使用原理类似make的方式
  11. slice3 := []int{1, 4, 7}
  12. 复制代码

切片的遍历

  • 代码展示
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //定义切片:
  5.    slice := make([]int,4,20)
  6.    slice[0] = 66
  7.    slice[1] = 88
  8.    slice[2] = 99
  9.    slice[3] = 100
  10.    //方式1:普通for循环
  11.    for i := 0;i < len(slice);i++ {
  12.        ("slice[%v] = %v \t" ,i,slice[i])
  13.   }
  14.    ("\n------------------------------")
  15.    //方式2:for-range循环:
  16.    for i,v := range slice {
  17.        ("下标:%v ,元素:%v\n" ,i,v)
  18.   }
  19. }
  20. 复制代码

结果:

切片注意事项

  • 切片定义后不可以直接使用,需要让其引用到一个数组,或者make一个空间供切片来使用
  • 切片使用不能越界
  • 简写方式:
  1. var slice = arr[0:end]  ----> var slice = arr[:end]
  2. var slice = arr[start:len(arr)]  ---->  var slice = arr[start:]
  3. var slice = arr[0:len(arr)]   ----> var slice = arr[:]
  4. 复制代码
  • 切片可以继续切片
  1. var intarr [6]int = [6]int{3, 6, 9, 1, 4, 7}
  2. slice := intarr[1 : 5]
  3. //再切片
  4. slice2 := slice[1 : 3]
  5. (slice2) //[9 1]
  6. 复制代码
  • 切片可以动态增长
  1. package main
  2. import "fmt"
  3. func main(){
  4.    //定义数组:
  5.    var intarr [6]int = [6]int{1,4,7,3,6,9}
  6.    //定义切片:
  7.    var slice []int = intarr[1:4] //4,7,3
  8.    (len(slice))
  9.    slice2 := append(slice,88,50)
  10.    (slice2) //[4 7 3 88 50]
  11.    (slice)
  12.    //底层原理:
  13.    //1.底层追加元素的时候对数组进行扩容,老数组扩容为新数组:
  14.    //2.创建一个新数组,将老数组中的4,7,3复制到新数组中,在新数组中追加88,50
  15.    //3.slice2 底层数组的指向 指向的是新数组
  16.    //4.往往我们在使用追加的时候其实想要做的效果给slice追加:
  17.    slice = append(slice,88,50)
  18.    (slice)
  19.    //5.底层的新数组 不能直接维护,需要通过切片间接维护操作。
  20. }
  21. 复制代码
  • 切片的拷贝
  1. //定义切片:
  2. var a []int = []int{1,4,7,3,6,9}
  3. //再定义一个切片:
  4. var b []int = make([]int,10)
  5. //拷贝:
  6. copy(b,a) //将a中对应数组中元素内容复制到b中对应的数组中
  7. (b)
  8. 复制代码

第九章:映射

map的引入

  • 映射(map), Go语言中内置的一种类型,它将键值对相关联,我们可以通过键 key来获取对应的值 value。 类似其它语言的集合
  • 基本语法
  1. var map变量名 map[keytype]valuetype 如:
  2. var a map[int]string
  3. 复制代码

PS:key、value的类型:bool、数字、string、指针、channel 、还可以是只包含前面几个类型的接口、结构体、数组 PS:key通常为int 、string类型,value通常为数字(整数、浮点数)、string、map、结构体 PS:key:slice、map、function不可以

  • 代码

    • map集合在使用前一定要make
    • map的key-value是无序的
    • key是不可以重复的,如果遇到重复,后一个value会替换前一个value
    • value可以重复的
  1. package main
  2. import "fmt"
  3. func main(){
  4.        //定义map变量:
  5.        var a map[int]string
  6.        //只声明map内存是没有分配空间
  7.        //必须通过make函数进行初始化,才会分配空间:
  8.        a = make(map[int]string,10) //map可以存放10个键值对
  9.        //将键值对存入map中:
  10.        a[20095452] = "张三"
  11.        a[20095387] = "李四"
  12.        a[20097291] = "王五"
  13.        a[20095387] = "朱六"
  14.        a[20096699] = "张三"
  15.        //输出集合
  16.        (a)
  17. }
  18. 复制代码

map的创建方式

  1. package main
  2. import "fmt"
  3. func main(){
  4.    //方式1
  5.    //定义map变量:
  6.    var a map[int]string
  7.    //只声明map内存是没有分配空间
  8.    //必须通过make函数进行初始化,才会分配空间:
  9.    a = make(map[int]string,10) //map可以存放10个键值对
  10.    //将键值对存入map中:
  11.    a[20095452] = "张三"
  12.    a[20095387] = "李四"
  13.    //输出集合
  14.    (a)
  15.    //方式2
  16.    b := make(map[int]string)
  17.    b[20095452] = "张三"
  18.    b[20095387] = "李四"
  19.    (b)
  20.    //方式3
  21.    c := map[int]string{
  22.        20095452 : "张三",
  23.        20098765 : "李四",
  24.   }
  25.    c[20095387] = "王五"
  26.    (c)
  27. }
  28. 复制代码

本文章借鉴:2022年GO语言全套精讲系列【入门精通】(96集),GO语言全栈开发进阶,入门到就业全靠它!哔哩哔哩bilibili