Go语言不太快速的入门(1),详解向文章| 青训营笔记

84 阅读7分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第2天。

Go语言的标识符

概念

   1.golang对各种变量、方法、函数等命名时使用的字符序列称为标识符
   2.凡是自己可以起名字的地方都叫标识符

命令规则

   1.26个英文字母大小写,0-9数字,_组成
   2.数字不可以开头
   3.golang中严格区分大小写
   4.标识符不能包含空格
   5.下划线在go中是一个特殊的标识符,称为空标识符,可以代表任何其他的标识符,但是它对应的值会被忽略
   (例如:忽略某个返回值),所以仅能作为占位符,不能作为标识符
   6.不能以系统关键字作为标识符,break7.go中有一个预声明的标识符nil,表示指针、通道、函数、接口、映射或切片类型等的空值,可以被赋值

注意事项

   1.包名:保持package的名字和目录保持一致,不要和标准库命名冲突
   2.采用驼峰式写法
   3.如果变量名、函数名、常量名首字母大写,则可以被其他的包访问,如果首字母小写,
     则只能在本包中使用,即首字母大写是公开(public)的,首字母小写是私有(private)的,这一点可以和java类比

Go较为独特的循环语句、跳转控制语句

三种for循环

go语言有一点是较为特殊的,它没有while循环,取而代之的是多种的for循环语句。

第一种for循环,和java、c++类似:

for i := 1; i <= 10; i++{
   fmt.Println("hello", i)
}

第二种for循环,类似while:

j := 1
for j <= 10{
   fmt.Println("hello", j)
   j++
}

第三种for循环,类似do while:

k := 1
for{
   if k <= 10{
      fmt.Println("ok~")
   } else {
      break
   }

跳转控制中的goto

go中有类似汇编语言的goto语法,可以直接跳转到程序的某一行,实际上这种语法java中也有,但和java一样,由于这种语法常造成程序的混乱,并不常用,但如果你之前只比较熟悉Python,这一部分还是有一定阅读的价值的。

对于goto:
1.go语言的goto语句可以无条件地转移到程序中指定的行
2.goto语句通常与条件语句配合使用,可以实现条件转移,跳出循环体等功能
3.在go程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难 基本语法:

goto label   
...
label:statement

例如:

var n int = 50
print("hell1")
if n > 20 {
   goto label1
}
print("hell2")  // 不执行了
print("hell3")   // 不执行了
print("hell4")   // 不执行了
label1:
print("hell5")
print("hell6")

函数与包

函数

基本语法

func 函数名 (形参列表) (返回值列表){
   执行语句
   return 返回值列表
}

注意事项

1.形参列表和返回值列表的数据类型可以是值类型,也可以是引用类型
2.基本数据类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值
3.首字母大写为public,可以被其他包使用,如果小写为private,不能被其他包使用
4.如果希望函数内的变量能修改函数外的变量(默认是以值类型传递的),可以传入变量的地址&,函数内以指针的方式操作变量
5.go函数不支持重载
6.在go中,函数也是一种数据类型,可以赋给一个变量,则该变量就是一个函数类型的变量了,通过该变量可以对函数调用
比如这样:

func myFun(funvar func(int, int) int, num1 int, num2 int) int {
   return funvar(num1, num2)
}

res2 := myFun(getSum, 20, 70)
fmt.Println(res2)

7.go支持自定义数据类型
基本语法:

type 自定义数据类型名 数据类型     相当于一个别名
如:type mySum func(int, int)int

8.支持对函数返回值命名

func cal(n1 int, n2 int) (sum int, sub int) {
   sum = n1 + n2
   sub = n1 - n2
   return          //此时就不用再声明要返回的值了
}

此时编译器在运行该函数时,会开始就根据指定的类型创建返回值,初始默认为0

8.使用_标识符,忽略返回值
9.go支持可变参数

   func sum(n1 int, args... int) int  {

   }
   args是slice切片,通过args[index]可以访问到各个值

函数参数的传递方式

值类型和引用类型

值类型包括:基本数据类型 int系列、float系列、bool、string、数组、结构体struct
引用类型:指针、slice切片、map、管道chan、interface等

值类型:变量直接存储值,内存通常在栈中分配
引用类型:变量存储的是一个地址,这个地址指向的空间才是真正存储的数据(值),内存通常在堆上分配,当没有任何变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,由GC来回收

两种传递方式:

1.值传递
2.引用传递

传递的都是变量的副本,值传递拷贝值,引用传递拷贝地址,一般来说,地址拷贝效率高,因为数据量小

包的本质实际上就是创建不同的文件夹,来存放程序文件

作用: 1.区分相同名字的函数、变量等标识符
2.当程序文件很多时,可以很好的管理项目
3.控制函数、变量等访问范围,即作用域

package指令在文件第一行,然后是import指令

基本语法:
打包:package 包名(不需要和文件夹名保持一致)
引入包:import "包的路径"
路径从$GOPATH 下的src下开始,不用带src,编译器会自动从src包下开始引入

   import{
      "fmt"
      utils "go_code/base_part/for_cyclic/utils"
   }

如果要编译成一个可执行文件,需要将这个包声明为main,即package.main 这是一个语法规范,如果写的是一个库,包名可以自定义

特殊函数与闭包

init函数

每一个源文件都可以包含一个init函数,该函数会在main函数执行前被Go运行框架调用,就像__init__之于Python中的类一样。

注意事项

1.如果一个文件同时包含全局变量定义、init函数和main函数,则执行流程是变量定义 -> init函数 -> main函数
2.init主要作用是完成初始化工作
3.被引入文件的变量定义、init函数的执行顺序先于主文件

匿名函数

如果某个函数只是希望使用一次,就可以考虑使用匿名函数,匿名函数也可以多次调用。

使用方式1: 在定义匿名函数时就直接调用

   res := func(n1 int, n2 int) int {
      return n1 + n2
   }(10, 20)

使用方式2:
将匿名函数赋给一个变量(函数变量),再通过该变量来调用匿名函数

a := func(n1 int, n2 int) int {
return n1 - n2
}

res2 := a(10, 4)
fmt.Println(res2)

全局匿名函数:
将匿名函数赋给一个全局变量,则成为一个全局匿名函数,可以在程序中有效

// 全局匿名函数
var (
Fun1 = func(n1 int, n2 int) int {
   return n1 * n2
}
)
res3 := Fun1(4, 7)
fmt.Println(res3)   // 这两行在main函数中

闭包

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

以一个累加器为例:

func AddUpper() func(int) int {
   var n int = 10
   var str = "hello"
   return func(x int) int {
      n += x
      str += "a"
      fmt.Println(str)
      return n
   }
}

返回的数据类型是func (int) int
闭包返回的是一个函数,但是该函数引用到了函数外的n,因此这个函数与n形成了一个整体,构成闭包
可以理解为闭包是一个类、函数是操作,n是字段
n只会初始化一次,在调用过一次后,n的值就会永远改变了
闭包 = 函数 + 变量 函数的返回结果影响变量的值

小应用(伪代码)

文件后缀自动补全

   func makeSuffix(suffix string) func(string) string{

      return func (name string) string {
         if !strings.HasSuffix(name, suffix) {
            return name + suffix
         }
         return name
      }
   }
匿名函数和suffix变量成为了一个闭包

Go的defer机制

在函数中,常常需要创建资源,比如数据库连接、文件句柄、锁等,为了在函数执行完毕后,及时的释放资源,go的设计提供了defer(延时机制)
加上defer,函数在执行完毕之后,指定的资源会被关闭

1.当代码执行到defer时,会先不执行其后的内容,而先让编译器将defer后的内容压入到独立的栈(可理解为一个defer栈)中,再执行之后的语句
2.当函数执行完毕后,再从defer栈,从栈顶按先入后出的方式出栈执行
3.在defer语句放入到栈时,会将相关的值拷贝同时入栈

主要用途(伪代码):
关闭文件 defer file.close()
释放数据库资源 defer connect.close()
优点:这是一种简洁的机制,使得开发者不必关心要在什么时候关闭资源

以上内容若有不正之处,恳请您不吝指正!