美文网首页
Go语言 函数

Go语言 函数

作者: 小杰的快乐时光 | 来源:发表于2018-08-18 22:19 被阅读0次

    函数的一般结构组成如下所示

    func function_name( [parameter list] ) [return_types] {
       函数体
    }
    函数定义解析:
    * func:函数由 func 开始声明
    * function_name:函数名称,函数名和参数列表一起构成了函数签名。
    * parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
    * return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
    * 函数体:函数定义的代码集合。
    

    比如下面这个返回int类型的函数

    /* 函数返回两个数的最大值 */
    func max(num1, num2 int) int {
       /* 声明局部变量 */
       var result int
       if (num1 > num2) {
          result = num1
       } else {
          result = num2
       }
       return result
    }
    

    函数的多返回值

    func main() {
       fmt.Println(Add(1,2))
    }
    
    func Add(a, b int) (sub int, err error) {
       if a < 0 || b < 0 {
          err = errors.New("a,b不同为负数")
          return 0,err
       }
       return a+b,nil
    }
    ----output-----
    3 <nil>
    

    关于函数的返回值命名
    Go语言中,返回值可以像被变量那样使用,在return没有返回值参数的情况下,会直接返回当前的计算值结果
    但是一般不在长函数中使用,会影响代码可读性。

    func main() {
       fmt.Println(sub(1))
    }
    
    func sub(num int)(x,y int)  {  //返回值是x,y
       if num >0 {
          x = num+2  //这里的x,y就是返回值中的x,y,被当作变量使用
          y = num-3
          return  //会直接返回x,y的计算值结果,与return x,y同效
       }
       return  //会返回int的默认值:0 , 0,与return 0,0同效
    }
    

    递归函数
    Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。

    语法格式如下:

    func recursion() {
       recursion() /* 函数调用自身 */
    }
    
    func main() {
       recursion()
    }
    

    计算阶乘
    ①普通for循环计算15的阶乘

    func main() {
       var j int  = 1
       for i:=15;i>0 ;i--  {
          j *=i
       }
       fmt.Println(j)
    }
    ---output---
    1307674368000
    

    ②使用Go的递归函数

    func Factorial(n int)(result int) {
       if n > 0 {  //跳出递归的条件
          result = n * Factorial(n-1) /* 函数调用自身 */
          return result
       }
       return 1
    }
    
    func main() {
       var i int = 15
       fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(i))
    }
    

    匿名函数与闭包
    闭包就是一个函数“捕获”和它在同一作用域的其他常量或变量。在Go语言中所有的匿名函数都是闭包。闭包的创建方式与普通函数在语法上几乎一致,但是闭包没有名字,通常都是将闭包赋值给一个变量,或者放到一个映射或切片中。

    func main() {
       c1 := f(0)
       c2 := f(0)
       fmt.Println(c1() )  // 1
       fmt.Println(c1() )  // 2
       fmt.Println(c2() )  // 1
    }
    
    // 闭包使用方法
    func f(i int) func() int {
       return func() int {
          i++
          return i
       }
    }
    

    分析:c1跟c2引用的是不同的环境,在调用i++时修改的不是同一个i,因此两次的输出都是1。函数f每进入一次,就形成了一个新的环境,对应的闭包中,函数都是同一个函数,环境却是引用不同的环境。

    下面这个例子中,每次调用的都是add_func(),因此i会递增

    func main() {
       add_func := add(1,2)
       fmt.Println(add_func())
       fmt.Println(add_func())
       fmt.Println(add_func())
    }
    
    // 闭包使用方法
    func add(x1, x2 int) func()(int,int)  {   
       i := 0
       return func() (int,int){  //匿名函数
          i++
          return i,x1+x2
       }
    }
    ----------output------------  只要闭包的还被使用,那么在闭包的变量会一直存在,比如 匿名函数中的i值
    1 3
    2 3
    3 3
    

    我们来看看一个使用闭包匿名函数与普通调用外部函数的区别

    func main() { //普通调用外部函数
       var j int  = 5
       a:= add(j) //这里得到一个函数a,i=10,j=5,里面有一个 fmt.Println(i,j)
       a() //这里 调用 fmt.Println(i,j),输出 10,5
       j*=2 //将j乘以2
       a() //这里依旧是以前的函数,i=10,j=5,j没有受影响
       a1:= add(j)  //这里将重新获得一个函数,此时i=10,j = 10
       a1() //输出10,10
    }
    
    func add(j int)func()  {
       var i int  = 10
       return func() {
          fmt.Println(i,j)
       }
    }
    -----output------
    10,5
    10,5
    10,10
    

    上面的 a在创建时引用的环境与a1引用的环境不同,而又因为j是值传递,因此在a创建时引用的环境中调用的是j的副本,这跟原本j的值是否改变无关。创建a1后,会引入新的j值的副本,因此a不会受影响,而a1会受影响

    func main() { 
       var j int  = 5
       a:= func() (func()){ //使用闭包匿名函数
          var i int  = 10
          return func() {
             fmt.Println(i,j)
          }
       }()  //这里加一个括号表示 函数调用
       a()
       j *= 2
       a()
    }
    -----output------  //这里输出受到了影响
    10 5 
    10 10
    

    这里闭包会捕获j的值,没有值传递的操作,因此在j的值改变后,调用a会受到影响

    相关文章

      网友评论

          本文标题:Go语言 函数

          本文链接:https://www.haomeiwen.com/subject/qcrqiftx.html