11 Golang函数详解

时间:2021-6-9 作者:qvyue

Go语言中支持:函数、匿名函数和闭包

  • 定义函数使用func关键字
func 函数名(参数)(返回值){
    函数体
}

注意:函数名由字母、数字、下划线组成,但不能以字母开头。在同一个包内,函数名不能重名

//求两个数的和
func sumFn(x int, y int) int {
    sum := x + y
    return sum
}

func main(){
    result := sumFn(12, 3)
    fmt.Println(result)//15
}

函数参数的简写(只能简写前面的)

func subFn(x, y int) int {
    return x - y;
}
函数的可变参数

可变参数其实是一个切片,通过在参数名后加...来标记,可变参数与固定参数结合使用时只能放在后面

//求n个参数的和
func sumFn1(x ...int)int{
    fmt.Printf("%v--%T", x, x)
    sum := 0
    for _,v := range x {
        sum += v
    }
    return sum
}
//[12 15 8 0]--[]int


func main(){
   result := sumFn1(12,15,8,0)
   fmt.Println(result)//35
}

注意,函数有返回值时,必须指定其类型

return关键字一次可以返回多个值
func calc(x, y int) (int, int){
    sum := x + y
    sub := x - y
    return sum, sub
}
func main(){
    sum,sub := calc(10, 2)
    fmt.Println(sum, sub)//12 8
}

返回值命名:函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return关键字直接返回

func calc(x, y int) (sum int, sub int){
//或func calc(x, y int) (sum, sub int){
    sum = x + y
    sub = x - y
    return
}

封装一个简单的选择排序(升序)

func sortIntAsc(slice []int) []int {
    for i := 0; i  slice[j] {
                temp := slice[i]
                slice[i] = slice[j]
                slice[j] = temp
            }
        }      
    }
    return slice
}

func main(){
    var sliceA = []int{1, 5, 3, 0}
    arr := sortIntAsc(sliceA)
    fmt.Println(arr)//[0 1 3 5]
}

对map按照key的ASCII进行升序排序

func mapSort(map1 map[string]string) string {
    var sliceKey []string
    //把map对象的key放到切片中
    for k, _ := range map1 {
        sliceKey = append(sliceKey, k)
    }
    //对key进行升序排序
    sort.Strings(sliceKey)
    //循环拼接字符串
    var str string
    for _, v := range sliceKey {
        str += fmt.Sprintf("%v=>%v ", v, map1[v])
    }
    return str
}

func main(){
    m1 := map[string]string{
        "username":"zhangsan",
        "age":"20",
        "sex":"男",
    }
    str := mapSort(m1)
    fmt.Println(str)
}
//age=>20 sex=>男 username=>zhangsan
函数变量作用域(同C语言)
  • 全局变量

定义在函数外部的变量,在整个程序的运行周期内都有效

  • 局部变量

在函数内部定义的变量,无法在外部使用

定义函数类型

使用type关键字来定义一个calulation类型的函数,它接收两个int类型的参数,并返回一个int类型的返回值

type calulation func(int, int) int

定义一个calc的类型

type calc func(int, int) int
type myInt int

func add(x, y int) int {
    return x + y
}
func test(){
    fmt.Println("test...")
}
func main(){
    var c clac
    c = add
    fmt.Printf("c的类型:%T", c) //c的类型:main.calc
    //c = test//这里报错了,因为test不满足calc的类型
    fmt.Println(c(10, 5)) //15
    
    f := add
    fmt.Printf("f的类型%Tn", f) //f的类型:func(int, int) int
    fmt.Println(f(15,5))//20
    
    var num1 int = 10
    var num2 myInt = 20
    fmt.Printf("num1的类型%T--num2的类型%Tn", num1, num2)
    //num1的类型int--num2的类型main.myInt
    fmt.Println(num1 + int(num2)) // 30
}
函数作为另一个函数的参数
type calcType func(int, int) int
func add(x, y int)int {
    return x + y
}

func calc(x, y int, cb calcType) int {
    return cb(x, y)
}

func main(){
    fmt.Println(calc(10, 20, add))//30
    mult := calc(3, 4, func(x, y int) int{
        return x * y
    })
    fmt.Println(mult)//12
}
匿名函数

匿名函数因为没有函数名,所以不能像普通函数那样调用,所以匿名函数需要保存到某个变量活着作为立即执行函数

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(4, 8)) //12
    b := do("*")
    fmt.Println(b(3, 4)) //12
}
函数的递归调用(与C一致,尽量避免递归)
函数的闭包

闭包是指有权访问另一个函数作用域中的变量的函数,可以让一个变量常驻内存且不污染全局变量。

func adder() func() int {
    var i = 10 //常驻内存,不污染全局
    return func() int {
        return i + 1
    }
}

func adder2() func(y int) int {
    var i = 10
    return func(y int) int {
        i += y
        return i
    }
}

func main(){
    var fn = adder()
    fmt.Println(fn())//11
    fmt.Println(fn())//11
    fmt.Println(fn())//11
    
    var fn2 = adder2()
    fmt.Println(fn(10))//20
    fmt.Println(fn(2))//22
    fmt.Println(fn(1))//23
}

注意:由于闭包的作用域中返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存。过度使用闭包会导致性能下降,所以,在非必要时不建议使用闭包。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。