others linux服务器运维 django3 监控 k8s golang 数据库 大数据 前端 devops 理论基础 java oracle 运维日志

golang 语言基础三

访问量:1187 创建时间:2021-02-01

golang函数定义、函数参数、函数返回值

函数定义

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)
}

Golang 切片、map当做函数参数、函数变量作用域

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))
}

函数变量作用域,全局变量定义在函数外部,在程序运行的整个周期有效。局部变量:函数内部定义的变量,无法在函数外部使用。

Golang函数作为参数 、函数作为返回值、匿名函数

定义函数类型: 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)
}

Golang函数递归、匿名函数、闭包

函数递归,函数调用自身

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))
}

Golang函数详解 defer panic recover

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("继续执行")
}
登陆评论: 使用GITHUB登陆