函数自定义
以下为函数定义格式:
func function_name( [parameter list] ) [return_types]{
//这里写函数体
}
实例(比较两个数的大小并返回最大值)
func max (num1,num2 int) int {
var result int
if num1>num2{
result = num1
}
else {
result = num2
}
return result
}
对函数的调用方式与c语言相同 Go函数可以返回多个值
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
函数参数传递有着值传递和引用传递两种传参方式 值传递是函数所做的修改不会改变实际参数的值,而引用(地址)传递则是会改变参数的值
type
type 关键字可以自定义类型
type Myint int //类型定义
//此时Myint已经是一个全新的类型了,不过它的特征或者说属性和int类型完全相同
type Myint= int//类型别名
//Myint此时就是int类型,而非一个全新的类型,此时他所指代的任然是int类型,只是相当于换了个名称称呼in而已
函数,具体格式如下
type calculation func(int, int) int
func add(a,b int)int{
return a+b
}
#定义函数类型后可以声明这种类型的变量并对其赋值
var c calculation
a:=1
b:=2
c=add(a,b)
#赋值后可以直接向调式函数一样使用这个变量
golang函数的骚
与c不同的是,go语言的函数也能作为形参或者返回类型(????)使用
//函数作为参数传入另一个函数
func add(x, y int) int {
return x + y
}
func calc(x, y int, op func(int, int) int) int {
return op(x, y)
}
//上面的声明:op作为形参名,后面的func(int,int) int表示op是一个需要两个int型变量传入返回值也是int的一个函数
func main() {
ret2 := calc(10, 20, add)
//这里直接向calc中传入了add函数
fmt.Println(ret2) //30
}
个人思考:结合上面的"type calculation func(int, int) int","op func(int, int) int"这一句可以写为op calculation
//函数作为返回类型的使用
func do(s string) (func(int, int) int, error) {
switch s {
case "+":
return add, nil
case "-":
return sub, nil
default:
err := errors.New("无法识别的操作符")
return nil, err
}
}
匿名函数与闭包
golang中还存在一种匿名函数
主要使用场景就是闭包,有两种调用方式
- 赋值给变量进行调用(闭包的使用场景)
var f=func(x int) int{ x+=1 return x } fmt.Println(f(2))//3 - 在函数后直接加上括号并传入值(闭包的原理基础?)
fmt.Println( func(x int) int{ x+=1 return x }(2) )//3
闭包的一大特征是以一个或多个函数作为另一个函数的返回值,即假设有一个C函数,他的返回值可以由函数A、B、D....等多个函数构成,此时若将声明的C函数赋值给变量V(假设此时C函数仅有1个返回值),这时V就可以作为返回的函数A被正常调用,若此时有一个变量V1,位于函数A外,函数C内,则V1的值在V被释放之前不会被释放
exp1:不带形参的函数C(返回值为一个带形参的的函数A)
package main
import "fmt"
func adder() func(int) int {
var x int = 0
return func(y int) int {
x += y
return x
}
}
func main() {
var f = adder()
fmt.Println(f(10), "/t", f(20), "/t", f(30))//10 30 60
}
上面的x就相当于变量V1,f相当于变量V,由于变量f位于main()函数体中,故直到main函数执行完成之前变量f存储的值不会被释放,x也包含在f内。(有点全局变量(伪)的意思)
exp2带形参的函数C(返回值为一个带形参的的函数A)
package main
import "fmt"
func adder(x int) func(int) int {
return func(y int) int {
x += y
return x
}
}
func main() {
var f = adder(10)
fmt.Println(f(10), "/t", f(20), "/t", f(30))//20 40 70
}
exp3:带参数的函数C(返回值为多个带参数的函数,A、B、C...)
func calc(base int) (func(int) int, func(int) int) {
add := func(i int) int {
base += i
return base
}
sub := func(i int) int {
base -= i
return base
}
return add, sub
}
func main() {
f1, f2 := calc(10)
fmt.Println(f1(1), f2(2)) //11 9
fmt.Println(f1(3), f2(4)) //12 8
fmt.Println(f1(5), f2(6)) //13 7
}
函数体中的defer
Go中defer的用法是在放在一般语句的前面,在函数即将返回时,defer语句将按照定义的逆序执行,说人话就时在函数执行完其他所有除defer以外的语句后执行defer,且越早定义的defer语句越后执行
go语言的return(返回)函数的返回机制在底层的操作为先将要返回的变量的值赋予返回值,然后再执行RET命令(大概是返回操作?),而defer语句的执行时间就位于赋值以后,RET指令之前。如下图
用处:可以方便的将资源清理的语句放在函数中的任何位置,反正执行顺序一样
内置函数
| 内置函数 | 介绍 |
|---|---|
| close | 关闭各种channel(通道) |
| len | 获取长度 |
| make | 分配内存,只用于map、slice、chan三种类型的内存分配 |
| new | 也是分配内存 |
| append | 追加元素到数组或切片之中 |
| panic | 处理错误 |
| recover | 处理错误,但只能写在defer调用的函数里面 |
make和new
new函数只接受一个参数,这个参数是一个类型,并且返回一个指向该类型内存地址的指针。
new函数会把分配的内存置为零,也就是类型的零值
make函数仅用与map、chan、slice三种类型的分配,且返回值也是这三种类型本身而非他们的指针
make 只能用来分配及初始化类型为 slice、map、chan 的数据。new 可以分配任意类型的数据;
new 分配返回的是指针,即类型 Type。make 返回引用,即 Type;
new 分配的空间被清零。make 分配空间后,会进行初始化;常用的任然是make*