检查go语言版本:go version
go语言的环境信息:go env
go编译:go build main
go执行: go run main
单行注释 //
多行注释 /* */
变量的声明:var 变量名称 变量类型
变量的初始化:var 变量名称 变量类型 = 赋值
或者采用先声明后赋值
最常用的自动推导类型 :=
多重赋值 a,b,c := 1,2,3
匿名变量: 丢弃数据不进行使用 _ := 1
标准库中的fmt.Print() 格式化为字符串后直接输出
fmt.Println() 自带换行符
fmt.Printf() 格式化字符串带占位符
fmt.Scanf()使用这种写法 fmt.Scanf(“%d”,&age)
fmt.Scan()直接获取用户输入fmt.Scan(&age)
必须以一个字母或者下划线开头,后面可以跟任意数量的字母,数字或下划线
go中的关键字
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
true false iota nil
int
uint
float
bool byte rune string error
make len cap new append copy close delete
complex real imag
panic recover
recover
函数没有任何参数,它会返回一个接口类型的值。如果当前的 goroutine 处于 panic 状态,那么recover
将会终止该 panic 状态,并返回通过panic
函数传递的值。如果当前的 goroutine 不是处于 panic 状态,那么recover
将会返回 nil。在实际编程中,recover
通常与defer
结合使用,用于在程序遇到无法修复的错误时,保证程序能够正常退出并进行必要的清理工作。需要注意的是,recover
只能在defer
延迟函数中有效,无法在普通的函数中使用。
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获到了panic:", r)
}
}()
fmt.Println("开始处理")
doSomething()
fmt.Println("处理完成")
}
func doSomething() {
fmt.Println("进行一些操作")
panic("发生了一个严重错误")
fmt.Println("操作完成")
}
好的命名 :见名知意 驼峰命名法
bool byte rune int uint float complex uintptr string
bool 类型真假
byte 字符类型单个字符 转义字符
string 字符串类型
格式化的输入输出
定义常量用const 字面常量
iota枚举 自动++
运算符:算术运算符 优先级:先乘除后加减,有括号先算括号里的,相同级别的从左至右运算
类型转换
Go语言中不允许隐式转换,所有类型转换必须显式声明(强制转换),而且转换只能发生在两种相互兼容的类型之间
强制类型转换的语法格式:数据类型名(待转换的值)
赋值运算符: = += -= *= /= %=
关系运算符:== != < > <= >=
逻辑运算符:! && || & *
顺序结构,选择结构,循环结构
if结构:一种的判断
if -else 结构适合:两种情况的判断
if -else if 结构适合: 多种情况判断,并且判断都是对区间中的数据进行判断
switch结构
switch-case 自带break
想执行完成某个case后,强制执行后面的case,可以使用fallthrough
循环结构:
for 表达式1;表达式2;表达式3 {
循环体
}
表达式1:定义一个循环的变量,记录循环的次数
表达式2:一般为循环条件,循环多少次
表达式3:一般为改变循环条件的代码,使循环条件终有一天不再成立
跳转语句:break continue goto
循环嵌套:尽量不要多层嵌套,性能比较低
传参:
func Test(a int, b int) {
fmt.Printf("a=%d,b=%d",a,b)
}
func main() {|
Test(3,5)
}
传不定个数参数列表:不定参数一定要放在最后
(a int,args …int)
在函数进行调用时,固定参数必须传值,不定参数可以根据需要来决定是否要传值.
函数的嵌套调用
函数的返回值:定义,返回多个返回值
函数类型:
将函数作为一种类型可以用来定义变量
func Test(a int, b int) (sum int) {
sum = a+b
return sum
}
type FuncType func(a int, b int) int
func main(){
var s int
var result FuncType
result = Test
s = result(3,6)
}
type关键字后面跟着类型的名字(FunType),FunType就是一个类型,那么FunType是一个函数类型,因为FunType后面跟着func(用来定义函数的),但是注意的是没有函数的名字.那么FunType是一个需要传递两个整型参数,有一个整型返回值的函数类型
既然函数类型类似于我们前面学习过的 int ,string 等类型,那么函数类型可以用来定义变量。
var result FuncType //表示定义了一个变量叫result,该变量的 类型是FuncType类型,而该类型是一个函数类型。
下面我们可以使用result这个函数类型的变量来调用函数了。
result=Test //将要调用的函数的名字赋值给result变量(也可以理解成将result变量指向了要调用的函数),这里要注意的是:第一:Test后面不能加括号。第二:函数类型变量result要和将要调用的函数Test保持一致,所谓一致就是我们定义的函数类型FuncType的变量result,只能调用参数是两个整型的,并且有一个返回值,而且也是整型的函数。那么Test函数完全满足要求。
现在已经完成了函数类型变量result指向了函数Test,那么我们可以使用函数类型的变量result调用函数:
result(3,6)//完成函数的调用。
函数的作用域:
局部变量 全局变量
匿名函数: 没有函数名字
匿名函数可以直接访问main()函数中的定义的局部变量,并且在匿名函数中对变量的进行修改是有效的
匿名函数的其他调用方法:(花活)
var num int
num = 9
f := func(){
num++
fmt.Println("niminghanshu :",num)
}
type FuncType func() //函数无参数无返回值与匿名函数相同
var f1 FuncType
f1 = f
f1()
fmt.Println("main函数",num)
实际上匿名函数只要在末尾加()即可实现调用
在括号中加入()参数即可实现传参
匿名函数最主要的功能就是实现了闭包
闭包:指有权访问另一个函数作用域中的变量的函数,就是在一个函数内部创建另一个函数
匿名函数(闭包),有一个很重要的特点:
它不关心这些捕获了的变量和常量是否有已经超出了作用域,所以只有闭包还在使用它,这些变量就会依然存在
延迟调用defer
代码逻辑越复杂,defer使用也越重要
同理,进行网络编程时,最后也要关闭整个网络的链接,也会用到defer
defer的执行顺序
一个函数中有多个defer语句,他们会以LIFO(后进先出)的顺序执行
defer+匿名函数
func f1() (r int) {
defer func(){
r++
}()
r = 0
return
}
func main() {
i := f1()
fmt.Println(i)
}
递归函数:
不断调用自身