函数
基本概念
基本语法
return
函数使用细节
- go函数形参和返回值列表都可以是多个、且数据类型可以是值类型也可以是引用类型
- 函数名首字母大写表示公有、小写表示私有
- 基本数据类型和数组都是值传递 (值拷贝),在函数内修改不会影响到原来的值
如果希望函数内修改函数外的值,需要使用指针,传递地址
func test1(x int){
x++
fmt.Printf("test1 : %d\n",x)
}
func test2(x *int){
*x++
fmt.Printf("test2 : %d\n",*x)
}
func main() {
var x int = 10
test1(x)
fmt.Println(x)
test2(&x)
fmt.Println(x)
}
go不支持函数重载
- 函数也是一种数据类型,可以赋值给一个变量,通过该变量就可以实现函数的调用 ```go func test1(x int){ x++ fmt.Printf(“test1 : %d\n”,x) } func main() { var func1 = test1 func1(100) }
//输出 test1 : 101
函数也可以作为一种形参,并且调用
```go
func test1(x int){
x++
fmt.Printf("test1 : %d\n",x)
}
func test2(add func(int),x int){
add(x)
}
func main() {
test2(test1,100)
}
//输出 test1 : 101
Go支持自定义数据类型
type mySum func(int,int) int //mySum等价于一个函数类型func(int,int) int
Go支持对函数返回值命名
func cal(n int,n2 int)(sum int,sub int){
sum = n1 + n2
sub = n1 - n2
return
}
可以用下划线 _ 忽略一个或多个返回值
- go 支持可变参数,放于参数列表最末
args… 数据类型 (args是slice切片,通过args[index]可以访问到各个值)
func sum(args... int){
re := 0
for i:=0;i< len(args);i++ {
re += args[i]
}
fmt.Println(re)
}
func main() {
sum(1,2,3,4,5,6,7)
}
// 输出 : 28
- 变量作用域
- 函数内部定义的变量叫局部变量,作用域仅在函数内部
- 函数外部定义的变量叫全局变量,作用域在整个包都有效,如果其首字母大写
则作用域在整个程序都有效。 - 如果一个变量在一个代码块,如for/if,那么这个变量的作用域在该代码块
init函数
通常可以在init函数中完成初始化工作
- 如果一个文件中包含全局变量定义、init函数、main函数,则执行流程为
全局变量定义=》init函数=》main函数
- 外部导入执行顺序
匿名函数
- 仅调用一次
- 通过变量多次调用
闭包
闭包就是一个函数与其相关的引用环境组合成一个整体
func AddUpper() func(int) int{
var n = 10
return func (x int) int {
n = n + x
return n
}
}
func main() {
f := AddUpper()
fmt.Println(f(1))
fmt.Println(f(2))
fmt.Println(f(3))
}
//输出
11
13
16
理解:
var n = 10
return func (x int) int {
n = n + x
return n
}
就算是一个闭包。可以理解为: 闭包是类、函数是操作、n是字段。
案例:
只需要传递一次后缀返回闭包,不用每次都传递后缀。
func makeSuffix(suffix string) func(string) string{
return func(name string) string {
if strings.HasSuffix(name,suffix){
return name
}
return name + suffix
}
}
func main() {
var myfun = makeSuffix("后缀")
fmt.Printf(myfun("一个后缀")+"\n")
fmt.Printf(myfun("一个前缀")+"\n")
var myfun2 = makeSuffix("前缀")
fmt.Printf(myfun2("一个后缀")+"\n")
fmt.Printf(myfun2("一个前缀")+"\n")
}
defer
//当执行到defer语句时,吧defer后面的语句加到独立的栈中(defer栈)
//当函数执行完毕、或者发生异常时,会从栈中按照先入后出的方式出栈执行
func sum(n1 int,n2 int) int{
defer fmt.Println(n1)
defer fmt.Println(n2)
res := n1 + n2
fmt.Println(res)
return res
}
func main() {
sum(10,20)
}
//输出
30
20
10
//当涉及到值的时候,当时的值也会被拷贝
func sum(n1 int,n2 int) int{
defer fmt.Println(n1)
defer fmt.Println(n2)
res := n1 + n2
n1 = 0
n2 = 0
fmt.Println(res)
return res
}
//输出
30
20
10
包
- 通常包名和其所在文件夹名一致
- 要使用其他包中的函数和路径时,要先引入对应的包 import
- package在文件第一行,然后是import指令
在import包时,路径从 $GOPATH 的 src下开始,不用带src,编译器自动从src下开始
package main
import "go_code/package2"
//引入外部函数
func main() {
package2.Add(50,60)
}
大写函数为公有,小写函数为私有,跨包访问只能访问公有
别名可以给包起个别名,起别名后只能用别名访问
package main
import nickname "go_code/package2"
//别名
func main() {
nickname.Add(50,60)
}
同一包下不可以有相同函数名
- 如果要编译成一个可执行文件,就需要将包名声明为main
在 GOPATH 目录进行 build 操作生成可执行文件 go build main包路径(从src下开始写路径)
配置路径 go build -o bin\my.exe(在GOPATH下的bin文件夹下生成my.exe) main包路径