zoukankan      html  css  js  c++  java
  • Go笔记-函数

    【函数定义】

            func function_name([parameter1 type,parameter2 type])[return_value1 return_type1,return_value2 return_type2,...]{
                //TODO
            }
            func : 函数有func开始声明
            function_name : 函数名称,函数名和参数列表一起构成函数签名
            parameter_list : 参数列表,参数就像是一个占位符,当函数被调用时,你可以将值船体给参数,这个值被称为实际参数。
                            参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
            return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
            函数体:函数定义的代码集合
        备注:除了main() init()函数外,其他的函数尊循以上格式

    【函数类型】

      Go中有三种类型:
    • 普通的带有名字的函数
    • 匿名函数或者lambda函数
    • 方法(Method)(与结构体有关)
    • 特殊的有main(),init()函数

    【函数的书写格式及调用说明】

      简单举例,如果没有参数、参数类型、返回值,返回类型等,可以省略  
      func functionName(){  // 大括号必须和函数声明同行
          // TODO
      }
      使用方式:调用
      package.FunctionName(arg1,arg2...)  // 包中的函数若想被外部调用,函数必须首字母大写
      使用方式:声明
      type binOp func(int,int) int
     
         调用说明:
    • 包中的函数若想被外部调用,函数必须首字母大写
    • Go中函数重载是不被允许的,会导致一个编译错误
    • 函数也可以作为一个函数类型来声明
    • 函数可以赋值给变量
    • 一个变量不能被赋值不同的函数,就像一个变量不能被声明多次一样的道理
    • Go没有泛型的概念
    • 函数不能在其他函数里嵌套声明,也就是说不能再函数体内声明(创造)函数,一般在函数体内使用匿名函数来完成这个
    • 函数值之间可以互相比较,如果它们引用的是相同的函数或者都是nil的话,则认为它们是相同的

    【函数的参数】

        按值传递:就是形参
        引用传递:按变量的内存地址传递,即取变量的内存地址,可以说就是指针,&变量,例如&a
        在函数调用中:切片(slice)字典(map)接口(interface)通道(channel)这样的引用类型都是默认使用引用传递(没有显式的指出指针)
        
        备注:在函数返回值多的时候,可以使用切片(返回值具有相同类型)或者结构体(返回值具有不同类型)

    【函数的返回值】

        命名返回值:作为结果形参(result parameters)被初始化为响应类型的零值,当需要返回的时候,我们只需要一条简单的return。命名返回值 需要用()括起来,即使只有一个 func funcName()(ret int){}
        非命名返回值:作为结果形参,需要返回的时候,return 后面需要跟返回的内容,多个非命名返回值 需要用括号()括起来,一个的时候不需要括起来,func funcName()(int,int)
     1 // 举例
     2 package main
     3  
     4 import "fmt"
     5  
     6 var num int = 10
     7 var numx2, numx3 int
     8  
     9 func main(){
    10     numx2, numx3 = getX2AndX3(num)
    11     PrintValues()
    12     numx2, numx3 = getX2AndX3_2(num)
    13     PrintValues()
    14 }
    15  
    16 func PrintValues(){
    17     fmt.Printf("num = %d, 2x num = %d, 3x num = %d
    ", num, numx2, numx3)
    18 }
    19  
    20 func getX2AndX3(input int)(int, int){ // 定义了函数返回的参数个数及参数类型
    21     return 2 * intput, 3 * input
    22 }
    23  // 使用了命名返回值
    24 func getX2AndX3_2(input int)(x2 int, x3 int){
    25     x2 = 2 * input
    26     x3 = 3 * input
    27     // return x2, x3    
    28     return  // 因为使用了命名返回值,所以return的时候,就按照命名返回值的变量返回。
    29
    备注:尽量使用命名返回值,使代码更加清晰,提高可读性
     

    【传递变长参数】

         如果函数的最后一个参数是采用...type(type表示数据类型)的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为0,这样的函数叫变长函数
      // 结构
      func myFunc(a,b,arg ...int){}
      // 事例及调用
      func Greeting(prefix string, who ...string)
      Greeting("Hello:","Joe","Anna","Robot")  // 变量who的值为[]string{"Joe","Anna","Robot"}
     
      在Greeting函数中,变量who的值为[]string{"Joe","Anna","Robot"}
      如果参数被存储在一个数组中arr,则可以使用arr...的形式传递参数调用 函数
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     x := min(1,3,2,0)
     7     fmt.Printf("The minimum is: %d
    ", x)
     8     arr := []int{7,9,3,5,1}
     9     x = min(arr...)
    10     fmt.Printf("The minimum in array arr is:%d",x)
    11 }
    12  
    13 func min(a ...int)int{
    14     if len(a) == 0 {
    15         return 0
    16     }
    17     min := a[0]
    18     for _, v := range a{
    19         if v < min {
    20             min = v
    21         }
    22     }
    23     return min
    24 }
     
        如果变长的参数类型不相同怎么办?
            使用结构体
      在这个结构体中存储任意类型的参数
      type Options struct{
          par1 type1,
          par2 type2,
          par3 type3,
      }
      // 使用
      FuncName(a,b,Option{par1:val1,par2:val2})
      使用空接口:该方案不仅可以用于长度未知的参数,可以用于不确定类型的参数,一般使用for-range循环,switch结构对每个参数的类型进行判断
      func typecheck(...,...,values ...interface{}){
          for _, value := range values{
              switch v := value.(type){
                  case int:...
                  case float:...
                  case string:...
                  case bool:...
                  default:...
              }
          }
      }
     
            

    【defer和追踪】

      关键字defer允许我们推迟到函数返回之前一刻,才执行被defer修饰的某个语句或者函数。类似其他语言中的finally
     1 // 示例
     2 package main
     3  
     4 import "fmt"
     5  
     6 func main(){
     7     funciton1()
     8 }
     9  
    10 func function1(){
    11     fmt.Printf("In function1 at the top
    ")
    12     defer function2()
    13     fmt.Printf("In function1 at the bottom
    ")
    14 }
    15  
    16 func function2(){
    17     fmt.Printf("function2:Defered until the end of the calling function!")
    18 }
    19  
    20 // 输出
    21 In function1 at the top
    22 In function1 at the bottom
    23 function2:Defered until the end of the calling function
        使用场景:
            关闭文件流,defer file.Close()
            解锁一个加锁的资源  defer mu.Unclock()
            打印最终报告 defer printFooter()
            关闭数据库链接 defer disconnectFromDB()
     
     

    【递归函数】

      演示斐波那契和阶乘
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     result := 0
     7     for i := 0; i<=10;i++{
     8         result = fibonacci(i)
     9         fmt.Printf(result)
    10     }
    11 }
    12  
    13 func fibonacci(n int)(ret int){
    14     if n < 2{
    15         ret = 1
    16     }else{
    17         ret = fibonacci(n-1)+fibonacci(n-2)
    18     }
    19     return
    20 }
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     var n int = 30
     7     result := factorial(n)
     8     fmt.Printf("n的阶乘是:%d",result)
     9     
    10 }
    11  
    12 func factorial(n int)(res int){
    13     if n > 0{
    14         res = n * factorial(n-1)
    15     }else{
    16         res = 1
    17     }
    18     return
    19 }
     
     

    【闭包的应用:将函数作为返回值】

        代码来展示Go中如何将函数作为返回值
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     func_param1 := add1(2)
     7     fmt.Println(func_param1(3))
     8     func_param2 := add2()
     9     fmt.Println(func_param2(3))
    10 }
    11  
    12 func add1(n int) func(a int) int{
    13     return func(a int) int{
    14         return a + n
    15     }
    16 }
    17  
    18 func add2() func(a int) int{
    19     return func(a int) int{
    20         return a + 2
    21     }
    22 }
    23  
    24 // 输出结果
    25 5
    26 5
        
        作为闭包的应用
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     var f = add()
     7     fmt.Println(f(10))
     8     fmt.Println(f(20))
     9     fmt.Println(f(30))
    10 }
    11  
    12 func add() func(a int) int{
    13     var x int
    14     return func(a int) int{
    15         x += a
    16         return x
    17     }
    18 }
    19 // 输出结果
    20 10
    21 30
    22 60
        这个程序说明变量x的值在三次调用函数类型变量f()时,都被操作了累积了
        
        下面使用闭包来实现斐波那契数列的程序,放弃递归的方法
     1 package main
     2  
     3 import "fmt"
     4  
     5 func main(){
     6     
     7     var i int
     8     f := fibonacci()
     9     for i = 0; i < 10; i++{
    10         fmt.Println(f(i))
    11     } 
    12 }
    13  
    14 func fibonacci() func(a int) int{
    15     var res int
    16     var last int
    17     var last_last int
    18     return func(a int) int{
    19         if a < 2{
    20             res = a
    21         }else{
    22             res = last_last + last
    23         }
    24         last_last = last
    25         last = res
    26         return res
    27     }
    28 }
     【学习参考处:https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md】
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    学习PyQt5(二):PyQt5布局管理
    学习PyQt5(一):安装PyQt5以及在PyCharm上配置PyQt5
    Day037--Python--线程的其他方法,GIL, 线程事件,队列,线程池,协程
    Day036--Python--线程
    Day035--Python--管道, Manager, 进程池, 线程切换
    Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue
    Day033--Python--进程
    Day032--Python--操作系统, process进程
    Day30--Python--struct, socketserver
    Day29--Python--缓冲区, 粘包
  • 原文地址:https://www.cnblogs.com/ymkfnuiwgij/p/7873462.html
Copyright © 2011-2022 走看看