zoukankan      html  css  js  c++  java
  • Golang 基础 06 -- 函数 function

    目录

    @

    Tips

    • Go函数不支持 嵌套,重载 和 默认参数
    • 但支持以下特性: 无需声明原型,不定长度变参,多返回值,命名返回值参数,匿名函数,闭包
    • 定义函数使用关键字func,并且左大括号不能另起一行

    函数定义,不定长变参,传递值类型与引用类型

    func main(){
    	a,b := 1,2
    	//传入值类型的拷贝,(int,string),不会改变这里的值
    	B(a,b)
    	fmt.Println("a,b=",a,b)
    	fmt.Println(A())
    	ss := []int{5,6,7,8}
    	//传入的参数是slice,是数组地址的拷贝,会改变这里的值,类似指针
    	C(ss)
    	fmt.Println("ss=",ss)
    }
    func A()(int, int, int){
    	a,b,c := 1,2,3
    	return a,b,c
    }
    func B(s ...int){
    	//a是个slice,不定长变参,只能作为最后一个参数
    	s[0]=3
    	s[1]=4
    	fmt.Println("s=",s)
    }
    func C(s []int){
    	s[0] = 55
    	s[1] = 66
    	s[2] = 77
    	s[3] = 88
    	fmt.Println(s)
    }
    /*
    > Output:
    command-line-arguments
    s= [3 4]
    a,b= 1 2
    1 2 3
    [55 66 77 88]
    ss= [55 66 77 88]
    */
    
    • 值类型传递和引用类型传递都是拷贝,但是值类型是拷贝值,而引用类型是拷贝地址

    一切皆类型,包括函数

    • Go语言中,一切皆类型,函数也能作为一种类型使用
    func main(){
    	a := A
    	a()
    }
    func A(){
    	fmt.Println("Func A")
    }
    /*
    > Output:
    command-line-arguments
    Func A
    */
    

    匿名函数和闭包

    匿名函数

    -匿名函数不能是最外层函数

    func main(){
    	a := func(){
    		fmt.Println("Func A")
    	}
    	a()
    }
    func A(){
    	fmt.Println("Func A")
    }
    /*
    > Output:
    command-line-arguments
    Func A
    */
    

    闭包

    • 闭包函数的作用:返回一个匿名函数
    func main(){
    	f := closure(10)
    	fmt.Println(f(1))
    	fmt.Println(f(2))
    }
    func closure(x int) func(int) int {
    	fmt.Printf("outside %p
    ", &x)
    	return func(y int) int {
    		fmt.Printf("%p
    ", &x)
    		return x * y
    	}
    }
    /*
    > Output:
    command-line-arguments
    outside 0xc042054080
    0xc042054080
    10
    0xc042054080
    20
    */
    

    defer用法

    • defer的执行方式类似其他语言的析构函数,在函数体执行结束后,按照调用顺序的相反顺序执行(好像递归返回那样吧)
    • 就算函数发生了严重错误也会执行
    • 支持匿名函数的使用
    • 常用于资源清理,文件关闭,解锁以及记录时间等操作
    • 通过与匿名函数配合可以在return之后修改函数结果
    • 如果函数体内某个变量作为defer时匿名函数的参数,则在定义时就已经获得拷贝,否则则是引用某个变量的地址
    func main(){
    	fmt.Println("a")
    	defer fmt.Println("b")
    	defer fmt.Println("c")
    }
    //a,c,b
    
    • 把return语句看做赋值+返回RET指令两部分,defer是插入在中间的,并且注意defer里面的函数操作的是返回值还是别的变量,匿名函数的参数是值传递还是引用传递,值传递就不会改变返回值啦
    • 参照大佬解析
    • 注意:defer后面定义的匿名函数要在最后加上(参数)
    func main(){
    	for i:=0; i<3; i++ {
    		defer func() {
    			fmt.Println(i)
    			}()
    	}
    	fmt.Println("a")
    	defer fmt.Println("b")
    	defer fmt.Println("c")
    }
    /*
    > Output:
    command-line-arguments
    a
    c
    b
    3
    3
    3
    */
    

    panic 与 recover,错误处理机制

    • Go没有异常机制,但是panic/recover模式来处理错误
    • panic可以在任何地方引发,但是recover只有在defer调用的函数
    func main(){
    	A()
    	B()
    	C()
    }
    func A() {
    	fmt.Println("Func A")
    }
    //defer要放在panic前面才有效,程序遇到panic就停了,所以要在这之前先注册defer的函数,且panic语句也不会执行了
    func B() {
    	defer func() {
    		if err:=recover(); err!=nil{
    			fmt.Println("recover in B")
    		}
    	}()
    	panic("panic in B")
    }
    func C() {
    	fmt.Println("Func C")
    }
    /*
    > Output:
    command-line-arguments
    Func A
    recover in B
    Func C
    */
    

    综合例子

    func main(){
    	var fs = [4]func(){}
    	for i := 0; i<4; i++ {
    	//值拷贝i+defer先进后出的输出
    		defer fmt.Println("defer i= ",i)
    		//引用拷贝(匿名函数没有参数,引用的i是外层的地址拷贝,为4)+defer
    		defer func() {fmt.Println("defer_closure i= ",i)}()
    		//引用拷贝(匿名函数没有参数,引用的i是外层的地址拷贝,为4)
    		fs[i] = func(){	fmt.Println("closure i= ",i)}
    	}
    	for _,f := range fs {
    		f()
    	}
    }
    /*
    > Output:
    command-line-arguments
    closure i=  4
    closure i=  4
    closure i=  4
    closure i=  4
    defer_closure i=  4
    defer i=  3
    defer_closure i=  4
    defer i=  2
    defer_closure i=  4
    defer i=  1
    defer_closure i=  4
    defer i=  0
    */
    
  • 相关阅读:
    UOJ.26.[IOI2014]Game(交互 思路)
    Good Bye 2016 F.New Year and Finding Roots(交互)
    Codeforces.835E.The penguin's game(交互 按位统计 二分)
    Codeforces.744B.Hongcow's Game(交互 按位统计)
    Codeforces.862D.Mahmoud and Ehab and the binary string(交互 二分)
    正睿OI 提高 Day1T3 ZYB玩字符串(DP)
    划分vlan
    2三层交换机实现vlan间的路由
    交换机基础-交换机远程telnet
    自动化运维环境的搭建问题处理
  • 原文地址:https://www.cnblogs.com/leafs99/p/golang_basic_06.html
Copyright © 2011-2022 走看看