- 一、空白标识符(下划线)
- 二、函数
- 2.1 函数的定义与调用
- 2.2 匿名函数
- 2.3 函数返回函数
- 2.4 闭包函数
- 三、装饰器
- 四、类型重命名
- 五、包管理
- 5.1 可见性
- 5.2 init 函数
- 六、模块(modules)
go 中_是一个特殊的标识符,用来忽略结果。它可以避免变量被定义,却没被使用时的报错。
-
在 import 中的作用:
如果只是想运行包内所有文件中的init()函数,而不需要导入包,则可以:
import _ "./hello" // hello 是包名
它只会执行包内所有文件中的init()函数,不会导入任何东西。
-
在其他地方中的作用:
比如,某个函数返回两个值,但我们只需要其中一个,那么用不到的值就可以用_来接收:
v,_ := foo(a,b)
_会被忽略,即便没有被使用,也不会报错。
-
函数定义方式:
// 有参数、有返回值 func 函数名(形参 类型, 形参 类型……)(返回值类型, 返回值类型……){ 函数体内容 return 返回值, 返回值…… } // 单个返回值可以不写括号 func 函数名(形参 类型, 形参 类型……) 返回值类型 { 函数体内容 return 返回值 } // 有参数、无返回值 func 函数名(形参 类型, 形参 类型……){ 函数体内容 // 如果返回一个值,就会报错 } // 多个参数类型相同,可以简写 func 函数名(a, b int, c string){ 函数体内容 } // 命名返回值 func 函数名()(a int, b string){ 函数体内容 a := 10 b := "hugh" return // 会自动返回 a,b } -
函数调用方式:
函数名(实参, 实参……)
在函数内部,只能定义命名函数。
-
匿名函数的定义:
func(形参 类型, 形参 类型……)(返回值类型, 返回值类型……){ 函数体内容 return 返回值, 返回值…… }()最后加了一对小括号是在调用匿名函数,和变量一样,匿名函数定义后不使用,同样会报错。
-
函数赋值给变量:
go 和 python 一样,函数都是一等公民,可以赋值给变量:
// 定义匿名函数,并赋值给 a a := func(i){ 函数体 } // 调用 a(6)
-
返回一个函数:
func foo() func(){ return func(){ fmt.Println("我是被返回的函数") } } // 调用 foo()() bar := foo() bar() -
返回一个有参数的函数:
func foo() func(msg string){ // 这里也要写返回值的参数 return func(msg string){ fmt.Println("我是被返回的函数") } }注意:在 go 中,类型只要有一丁点不同之处,就会认为这两种是不同的类型。
-
返回一个有参数有返回值的函数:
func foo() (func(msg string) int){ // 这里也要写返回值的参数,返回值 return func(msg string) int { fmt.Println("我是被返回的函数") return 1 } } -
函数的参数是函数,返回值为有参数有返回值的函数:
func foo(f func()) (func(msg string) int){ f() // 调用函数 return func(msg string) int { fmt.Println("我是被返回的函数") return 1 } }
- 定义在函数内部;
- 对外部作用域有引用。
func foo() func(){
age := 17
bar := func(){
fmt.Println(age) // 对外部作用域有引用
}
return bar
}
三、装饰器
装饰器是闭包函数的典型应用,go 只是没有像 python 那样的@语法糖,但完全能够实现装饰器。
无参装饰器:
func foo(f func()) func(){
bar := func(){
// 其他操作
f()
// 其他操作
}
return bar
}
a := foo(a) // a 是要被装饰的函数
a() // 正常调用
有参装饰器:
func foo(f func()) (func(x int)){
bar := func(x int){
// 其他操作
f()
// 其他操作
}
return bar
}
a := foo(a) // a 是要被装饰的函数
a(123) // 调用时传参
四、类型重命名
//type 名称 类型 type MyFunc func(a,b int)(int, string) type MyInt int
注意:重命名后的类型,就和原来的类型不是同一个类型了。
五、包管理包用于组织 Go 源代码,以获得更好的重用性和可读性。
每个可执行的 Go 程序都必须包含一个 main 函数。这个函数是执行程序的入口点。main 函数必须包含在 main 包中。
-
指定一个源文件所属于一个包:
package 包名 // 这条语句应该放在源文件的第一行
一个文件夹就是一个包,除了 main 包之外,其他包的名称建议和文件夹名称一致。
-
导入包:
go 代码必须放在 $GOPATH/src 下,导入包是从 $GOROOT/src 和 $GOPATH/src 开始找。
// 单行导入 import "包相对于 $GOPATH/src 的路径" // 多行导入 import ( "包1相对于 $GOPATH/src 的路径" "包2相对于 $GOPATH/src 的路径" ) // 设置别名 import 别名 "包相对于 $GOPATH/src 的路径" // 合并包到当前程序中 import . "包相对于 $GOPATH/src 的路径"
- 声明在函数内部,是函数的本地值。
- 声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值。因此,同一包下,变量、函数不能重名,但可以不用导入, 直接使用。
- 声明在函数外部且首字母大写是所有包可见的全局值。如果不大写,外部的包无法使用。
所有包都可以包含一个 init 函数,用来做一些包的初始化工作。init函数不应该有任何返回值类型和参数,也不能代码中显式地调用它。
包的初始化顺序如下:
- 首先初始化包级别(Package Level)的变量。
- 紧接着调用init函数。包可以有多个init函数(在一个文件或分布于多个文件中)。
如果一个包导入了另一个包,会先初始化被导入的包。尽管一个包可能会被导入多次,但是它只会被初始化一次。
六、模块(modules)go 语言在早期将所有的依赖包都放在 $GOPATH目录下,导致同一个库只能保存一个版本的代码。于是在1.11版本推出了 Go Module 依赖管理工具。
-
开启 go module,设置环境变量:
export GO111MODULE=on
-
初始化 go module:
在 $GOPATH目录外新建目录,并使用下面的命令生成 go.mod 文件:
go mod init 名称
名称建议使用项目名称。
-
增加缺少的包,删除无用的包:
go mod tidy
-
校验依赖:
go mod verify



