Hello World

go:函数

1. 简介

1.1 函数类型

  1. 普通带有名字的函数;

  2. 匿名函数或者 lambda 函数;

  3. 方法(Methods)

1.2 函数签名

  除了main()、init()函数外,其它所有类型的函数都可以有参数返回值。函数参数、返回值以及它们的类型被统称为函数签名

  go里面函数不允许重载,函数名需保证在包内的唯一性;

1.3 函数作为参数

  函数可以将其他函数作为它的参数,只要这个被调用函数的返回值个数、返回值类型和返回值的顺序与调用函数所需求的实参是一致的;

  示例:

package main

import "fmt"

func main()  {

    fun1(fun2())
}

func fun1(a int,b int,c int)  {
    fmt.Println(a,b,c)
}

func fun2()(a int,b int,c int)  {
    return 1,2,3
}
View Code

 1.4 函数类型

  函数也可以以申明的方式被使用,作为一个函数类型;

  函数类型可以赋值给变量,就像 add := binOp 一样,这个变量知道自己指向的函数的签名,所以给它赋一个具有不同签名的函数值是不可能的;

  函数值(functions value)之间可以相互比较:如果它们引用的是相同的函数或者都是 nil 的话,则认为它们是相同的函数;

type binOp func(int, int) int

 1.5 声明外部定义的函数

  如果需要申明一个在外部定义的函数,你只需要给出函数名与函数签名,不需要给出函数体:

func flushICache(begin, end uintptr) // implemented externally

 2. 函数参数和返回值

  go 语言的函数可以返回多个返回值,称为一组返回值;

  函数定义时,它的形参一般是有名字的,不过我们也可以定义没有形参名的函数,只有相应的形参类型,就像这样:func add ( int, int )

  没有参数的函数通常被称为 niladic 函数(niladic function),就像 main.main()

2.1 值传递和引用传递

  函数调用时默认采用值传递的方式传递参数,传递的都是变量的副本,函数中对参数副本的修改不影响参数的值;

  如果需要函数直接修改参数的值,可以传递参数的地址(即指针),这样函数就可以直接修改参数的值,传递参数地址的形式:&varName;

    传递指针赋予了函数改变外部变量的能力,还可以节省内存,被修改的变量也不用return

  传递参数地址的本质也是值传递,指针也是变量类型,有自己的地址和值,通常指针的值指向一个变量的地址。所以,按引用传递也是按值传递;

2.2 返回值命名

  尽量使用命名返回值:会使代码更清晰、更简短,同时更加容易读懂

  返回值只有数据类型,没有命名返回参数名称的时候,直接返回对应类型的值即可;

func func3()(int,int)  {
    return 2,3
}

  返回值命名了参数名称时,在对返回参数赋值后,直接return即可,不用显示return 返回参数,如果没有对返回参数进行赋值操作,则返回该参数类型的零值;

func main()  {

    i, i2 := func3()
    fmt.Println(i,i2)

    a1, a2 := func4()
    fmt.Println(a1,a2)

    a12, a22 := func5()
    fmt.Println(a12,a22)
}

func func3()(int,int)  {
    /**
        输出:2 3
     */
    return 2,3
}

func func4()(a1 int,a2 int)  {
    /**
    输出: a1:12  a2:13
     */
    a1=12
    a2=13
    return
}

func func5()(a1 int,a2 int)  {
    /**
        输出: a1:12  a2:0
     */
    a1=12
    a3:=13
    fmt.Println("temp var",a3)
    return
}

2.3 空白符_

  如果不需要某个返回值,可以将这个返回值赋值给空白符

2.4  变长参数

  类似于Java,变长参数必须作为参数列表中的最后一个,形式如下:

func func6(a int, s... int ) {

}

2.5 defer

  defer 的用法类似于 Java 的 finally,用于在函数执行完成后进行释放资源的操作;

  defer 关键字可以允许程序在 return 之后执行某个语句或者函数;

  如果一个函数内有多个 defer,则会按照 defer 的定义顺序的逆序执行;

  程序按照语句顺序执行到 defer 位置时,会先计算确定 defer 函数的参数(此处已经计算确定了参数值,后面就算再修改这个参数变量的值也不会影响 defer 函数调用时的参数值 ),然后在程序 return 后执行该函数;

  被 defer 的函数可以读取并修改有变量名的返回参数,一般配合匿名函数使用;

  示例:

package main

import "fmt"

func main() {

    deferOrder()
    defineDeferParamFuncValue()
    defineDeferParamValue()
    fmt.Println(modifyReturnParamValue())
}

func trace(s string) string {
    fmt.Println("entering:", s)
    return s
}

func un(s string) {
    fmt.Println("leaving:", s)
}
func deferOrder() {
    /**
        输出:
        in func deferOrder
        a2
        a1
     */
    defer fmt.Println("a1")
    fmt.Println("in func deferOrder")
    defer fmt.Println("a2")
}

func defineDeferParamFuncValue() {
    /**
        输出:
        entering: func defineDeferParamFuncValue
        in func defineDeferParamFuncValue
        leaving: func defineDeferParamFuncValue
     */
    // 程序执行到此处时,会先计算确定 defer 函数的参数,然后在程序 return 后执行该函数;
    defer un(trace("func defineDeferParamFuncValue"))
    fmt.Println("in func defineDeferParamFuncValue")
}

func defineDeferParamValue() {
    /**
        输出: 0
     */
    // defer 函数的参数在计算确定之后,即使参数发生变化,对已经 defer 函数的参数也没有影响
    i:=0
    defer fmt.Println("define defer param value:",i)
    i+=1
}

func modifyReturnParamValue() (x int) {
    defer func() { x++ }()
    x = 2
    return 3
}

 

posted @ 2020-05-19 18:28  小小忧愁米粒大  阅读(226)  评论(0编辑  收藏  举报
瞅啥瞅,好好看书