• Go语言学习笔记(五) [函数]


    日期:2014年7月29日
     
    1、函数定义:func (p type) funcname(q int) (r,s int) {return 0,0 }
        func: 保留字,用于定义一个函数
         (p type) :可选的,用于定义特定的函数类型,俗称方法。
        funcname:函数名
        (q int) :q作为输入参数,在Go中函数参数是按传值方式传递的。
        (r,s int):变量r,s是这个函数的命名返回值,在Go中函数可以返回多个值,如果不想对返回的参数命名,只需要提供类型:(int, int)。如果只有一个返回值,可以省略圆括号。如果函数是一个子过程,并且没有任何返回值,也可以省略这些内容
         {return 0,0 } :函数体。
    说明:函数的定义顺序可以随意安排,编译器会在执行前扫描每个文件。Go 不允许函数嵌套。然而你可以利用匿名函数实现它。
     
    2、函数递归的例子
    func rec(i int) {
     if i == 10 {
      return
     }
     rec(i+1)
     fmt.Printf("%d ",i)
    }
     
    3、函数的作用域
        在 Go 中,定义在函数外的变量是全局的,那些定义在函数内部的变量,对于函数来 说是局部的,局部变量仅仅在执行定义它的函数时有效。如果命名覆盖——一个局部变量与一个全局变量有相同的名字——在函数执行的时候,局部变量将覆盖全局变量。
        例如:
              package main
    var a = 6
    func main() {  
        p() 
        q()
        p()
        f()
        p()
    }
     
    func p() {
        print(a)
    }
    func q() {
        a := 5
        print(a)
    }
    func f() {
        a = 3
        print(a)
    }
    打印结果:65633
    解释:函数q()中对a做了定义,此时a的有效范围就是q()内,而函数f()中,a = 3全局有效的a重新赋值了。
     
    当函数调用函数时,作用域又是怎样的呢?来看下面这个例子:
    package main
     
    var a int
     
    func main() {
     a = 5
     print(a)
     f()
    }
    func f() {
     a := 3
     print(a)
     g()
    }
    func g() {
     print(a)
    }
    打印结果:535
    解释: 因为局部变量仅仅在执行定义它的函数时有效,所以g()中的a使用的是外部定义的全局变量。
     
    4、多值返回:和Python一样,Go也支持函数和方法返回多个值。
        例如:
        func manyvaluereturn(x,y int) (int,int){
                 return x,x+y
        }
        调用:
        x,z := manyvaluereturn(4,6)
        fmt.Printf("x=%d,z=%d",x,z)
        执行结果:x=4,z=10
     
    5、命名返回值
        Go 函数的返回值或者结果参数可以指定一个名字,并且像原始的变量那样使用,如同输入参数一般。如果对其命名,在函数开始时,它们会用其类型的零值初始化;如果函数在不加参数的情况下执行了 return 语句,结果参数的当前值会作为返回值返回。返回值的名字不是强制的,但是它们可以使得代码更加健壮和清晰。
        例如:
    示例一(没有命名返回值):
    func Factorial(x int) int {
      if x==0 {
       return 1
      } else {
       return x * Factorial(x-1)
      }
     }
    示例一(命名了返回值):
    func Factorial(x int) (result int) {
      if x==0 {
       return=1
      } else {
       return = x * Factorial(x-1)
      }
      return
     }
     
    对比示例一和示例二,哪种看起来更加清晰明白呢?
     
    6、变参:接受不定数量的参数的函数称为变参函数。例如:func funcname(arg ...int){},arg ...int表示这个函数接受变参,其参数类型全部是int,变量arg是一个int类型的slice。
     
    7、匿名函数与闭包
    1)匿名函数定义:不需要定义函数名的一种函数实现方式。
    2)Go语言支持随时在代码中定义匿名函数。
    3)匿名函数可以直接赋值给一个变量或者直接执行
    例如:
    package main
     
    import "fmt"
     
    func main() {
     func(x,y int) { //函数直接执行
      fmt.Println(x + y)
     } (5,6) //这里的参数列表表示函数调用
     
     f := func(x,y int) int { //匿名函数作为值赋值给f
      return x * y
     }
     
     result := f(8,10)
     fmt.Printf("result=%d",result)
    }
     
    4)闭包的概念: 闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)。
    5)闭包的价值:闭包的价值在于可以作为函数对象或者匿名函数,对于类型系统而言,这意味着不仅要表示 数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
    6)Go语言的闭包函数示例:
    func closefunc () {
     var j int = 5
     a := func() (func()) {
      var i int = 10
      return func () {
       fmt.Printf("i,j : %d,%d ",i,j)
      }
     }()
     a()
     j *= 2 //修改j的值
     a()
    }
    执行结果:
    i,j : 10,5
    i,j : 10,10
     
    说明:
    (1)变量a指向的闭包函数引用了局部变量j(closefunc的局部变量)和i(匿名函数的局部变量),i的值被隔离在匿名函数内,在闭包外不能修改。改变j的值,再次调用a,得到的结果是修改后的值。
    (2)在变量a指向的闭包函数中,只有内部的匿名函数有权访问变量i,因此保证了i的安全性。
     
    8、函数作为值
    可以把函数当成值赋值给一个变量。
    例如:a := func() { //这里是一个匿名函数
                   println("Hello!")
               }
     
    9、错误处理
    1)error接口:Go语言中引入了一个关于错误处理的标准模式,即error接口。
    对于大多数函数,如果要返回错误,大致可以定义为如下模式,将error作为多种返回值的最后一个(并非强制的)。
    func Foo(param int) (n int ,err error) {
    }
    调用是的代码建议按如下方式处理错误情况:
    n,err := Foo(0) 
    if err != nil {
         //错误处理
    } else {
        //使用返回值n
    }
    我们还可以自定义error类型,在此暂不介绍。
    2)defer
    (1)一个函数中可以存在多个defer语句,因此需要注意的是,defer语句的调用是遵照
    先进后出的原则,即最后一个defer语句将最先被执行。
    3)Panic(恐慌)和Recover(恢复)
    (1)Go 没有像 Java 那样的异常机制:不能抛出一个异常。作为替代,它使用了恐慌和恢 复(panic-and-recover)机制。
    (2)在代码中应当没有或者很少令人恐慌的东西。
     
  • 相关阅读:
    ASP.NET Core Docker部署
    Asp.Net Core 发布和部署(Linux + Jexus )
    Asp.Net Core 发布和部署( MacOS + Linux + Nginx )
    作为一个测试leader平时应该注意哪些方面
    【转】性能测试工具 性能测试如何做?
    【转】Grafana系列教程–Grafana基本概念
    jar包和war包的介绍和区别
    MySQL常用存储引擎
    【参】编程习惯
    【转】性能测试中如何定位性能瓶颈
  • 原文地址:https://www.cnblogs.com/javagoboy/p/3877614.html
Copyright © 2020-2023  润新知