函数定义
golang支持:函数、匿名函数、闭包
定义格式:
func 函数名(参数)(返回值){
函数体
}
package main
import "fmt"
func sumFn(x int, y int) int {
sum := x + y
return sum
}
// 参数类型相同,可以简写
func subFn(x, y int) int {
sub := x - y
return sub
}
//可变参数,参数数量不固定,通过在参数名后面加...来标示,可变参数的类型是切片
func sumFn1(x ...int) {
fmt.Printf("%v--%T\n", x, x)
}
// 多个返回值
func calc(x, y int) (int, int) {
sum := x + y
sub := x - y
return sum, sub
}
// 返回值命名
func calc1(x, y int) (sum, sub int) {
sum = x + y
sub = x - y
return
}
func main() {
fmt.Println(sumFn(11, 22))
sumFn1(1, 2, 3, 45, 6)
a, b := calc(5, 1)
fmt.Println(a, b)
}
package main
import (
"fmt"
"sort"
)
// int类型切片升序排序
func sortIntAsc(slice []int) []int {
for i := 0; i < len(slice); i++ {
for j := i + 1; j < len(slice); j++ {
if slice[i] > slice[j] {
temp := slice[i]
slice[i] = slice[j]
slice[j] = temp
}
}
}
return slice
}
//按map的key升序排序输出
func mapSort(map1 map[string]string) string {
var sliceKey []string
for k, _ := range map1 {
sliceKey = append(sliceKey, k)
}
sort.Strings(sliceKey)
var str string
for _, v := range sliceKey {
str += fmt.Sprintf("%v=>%v", v, map1[v])
}
return str
}
func main() {
var sliceA = []int{12, 21, 32, 432, 1, 433, 67, 34}
arr := sortIntAsc(sliceA)
fmt.Println(arr)
m1 := map[string]string{
"username": "张三",
"age": "22",
"sex": "男",
}
fmt.Println(mapSort(m1))
}
函数变量作用域,全局变量定义在函数外部,在程序运行的整个周期有效。局部变量:函数内部定义的变量,无法在函数外部使用。
定义函数类型: type calc func(int,int) int
上面语句定义了一个calc类型,是一种函数类型,这种函数类型接收两个int类型的参数并且返回一个int类型的返回值。
满足条件的函数都是calc类型的函数,下面的add是calc类型。
func add(x,y int) int {
return x+y
}
自定义类型
package main
import "fmt"
type calc func(int, int) int //定义calc类型,把一个方法(函数)自定义为类型
type MyInt int //自定义类型
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
func main() {
var c calc
c = add
fmt.Printf("c的类型: %T\n", c) //c的类型: main.calc ,自定义类型
fmt.Println(c(1, 2))
d := sub
fmt.Printf("d的类型: %T\n", d) //d的类型: func(int, int) int
var a int = 10
var b MyInt = 20
fmt.Printf("a:%T,b:%T", a, b)
fmt.Println(a + int(b))
}
方法作为函数参数:
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
//自定义一个类型
type calcType func(int, int) int
func calc(x, y int, cb calcType) int {
return cb(x, y)
}
func calc1(x, y int, op func(int, int) int) int {
return op(x, y)
}
func main() {
fmt.Println(calc(5, 1, add))
fmt.Println(calc1(5, 1, sub))
//匿名函数
j := calc(3, 4, func(x, y int) int {
return x * y
})
fmt.Println(j)
}
函数作为另一个函数的返回值:
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func sub(x, y int) int {
return x - y
}
type calcType func(int, int) int
func do(o string) calcType {
switch o {
case "+":
return add
case "-":
return sub
case "*":
return func(x, y int) int {
return x * y
}
default:
return nil
}
}
func main() {
var a = do("+")
fmt.Println(a(1, 2))
}
匿名方法、匿名函数
没有名字的函数,定义方法如下:
func(参数)(返回值){
函数体
}
package main
import "fmt"
func main() {
// 匿名函数 , 在最后加()表示调用,匿名自执行函数
func() {
fmt.Println("test...")
}()
// 匿名函数 赋值后调用
var fn = func(x, y int) int {
return x + y
}
fmt.Println(fn(1, 2))
// 匿名自执行函数接收参数
func(x, y int) {
fmt.Println(x, y)
}(1, 2)
}
函数递归,函数调用自身
package main
import "fmt"
func fn1(n int) {
if n > 0 {
fmt.Println(n)
n--
fn1(n)
}
}
//递归实现1-100的和
func fn2(n int) int {
if n > 1 {
return n + fn2(n-1)
}
return 1
}
func main() {
fn1(10)
fmt.Println(fn2(100))
}
闭包,可以理解为定义在一个函数内部的函数,本质上闭包是将函数内部和函数外部连接起来的桥梁,或者说是函数和其引用环境的组合体。
变量 | 特点 |
---|---|
全局变量 | 常驻内存,污染全局 |
局部变量 | 不常驻内存,不污染全局 |
闭包 | 可以让一个变量常驻内存,可以让一个变量不污染全局 |
闭包:1、指有权访问另一个函数作用域中的变量的函数。2、创建闭包常见的方式是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量
package main
import "fmt"
func adder() func(y int) int {
// i是局部变量,但是常驻内存,不污染全局
var i = 10
return func(y int) int {
i += y
return i
}
}
func main() {
var a = adder()
fmt.Println(a(1))
fmt.Println(a(2))
fmt.Println(a(10))
fmt.Println(a(10))
}
defer语句: Go的defer语句会将后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,先被defer的语句最后执行,最后被defer的语句最先执行。
defer执行时机: 在go语言函数中return 语句底层并不是原子操作,它分为对返回值赋值和ret指令两个操作。而defer语句执行的时机就在返回值赋值操作后,ret指令执行前。
package main
import "fmt"
func f1() {
fmt.Println("start1")
defer func() {
fmt.Println("abc")
}()
fmt.Println("end1")
}
// 调用f2()返回值为0, 匿名返回值,返回的是defer执行之前的值
func f2() int {
var a int
defer func() {
a++
}()
return a
}
// 命名返回值 ,返回值1,是defer执行之后的值
func f3() (a int) {
defer func() {
a++
}()
return a
}
func f4()(x int){
defer func(x int){
x++
}(x)
return 5
}
func main() {
//defer演示
fmt.Println("start")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("end")
f1()
fmt.Println(f2())
fmt.Println(f3())
fmt.Println(f4())
}
defer 注册要延迟执行的函数时,该函数所有的参数都需要确定其值:
package main
import "fmt"
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
// 注册顺序(注册时参数的值已经确定)
//calc("AA", x, calc("A", x, y))
//calc("BB", x, calc("B", x, y))
//执行顺序
//calc("BB", x, calc("B", x, y))
//calc("AA", x, calc("A", x, y))
//执行顺序:
//calc("A", x, y)
//calc("B", x, y)
//calc("BB", x, calc("B", x, y))
//calc("AA", x, calc("A", x, y))
x := 1
y := 2
defer calc("AA", x, calc("A", x, y))
x = 10
defer calc("BB", x, calc("B", x, y))
y = 20
}
defer panic recover异常处理:panic可以在任何地方引发,但recover只有在defer调用的函数中有效。
package main
import "fmt"
func fn1() {
fmt.Println("fn1")
}
func fn2() {
panic("抛出异常")
}
func main() {
fn1()
fn2() // 程序遇到panic会结束执行,并抛出异常,后面的end不会输出出来
fmt.Println("end")
}
通过recover监听panic异常,如果有异常,recover可以让程序继续执行
package main
import "fmt"
func fn1() {
fmt.Println("fn1")
}
func fn2() {
defer func() {
err := recover() //没有异常err=nil
if err != nil {
fmt.Println("err:", err)
}
}()
panic("抛出异常")
}
func main() {
fn1()
fn2()
fmt.Println("end")
}
例子2:
package main
import "fmt"
func fn1(a, b int) int {
defer func() {
err := recover()
if err != nil {
fmt.Println("err:", err)
}
}()
return a / b
}
func main() {
fmt.Println(fn1(10, 0))
}
经常使用的异常处理方式:
package main
import (
"errors"
"fmt"
)
//模拟一个读取文件的方法
func readfile(fileName string) error {
if fileName == "main.go" {
return nil
} else {
return errors.New("读取文件失败")
}
}
func myFn() {
defer func() {
err := recover()
if err != nil {
fmt.Println("错误信息:", err)
}
}()
err := readfile("xxxxxx.go")
if err != nil {
panic(err)
}
}
func main() {
myFn()
fmt.Println("继续执行")
}