golang第十四天,函数(中篇)

898 阅读4分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

1. 函数的返回值

一个函数被调用后,返回调用处的执行结果,叫做函数的返回值
调用处需要使用变量接收该结果

1. 一个函数可以返回多个值

  • 一个函数可以没有返回值,也可以有一个返回值,也可以有多个返回值
pageage main
import "fmt"
func local(s, y string)(string, string) {
    return y, x
}
func main() {
    a, b := local("xiaohe", "afei")
    fmt.Println(a, b)
} // afei, xiaohe

func product(A, B int) (add int, multiplied int) {
    add = A + B
    multiplied = A + B
    return
}  // nil

2. 空白标识符

_是go中的空白标识符。
它可以代替任何类型的任何值

比如rectPoints函数返回的结果是面积和周长,如果我们只要面积,不要周长,就可以使用空白标识符

package main
import "fmt"
func rectPoints(length, width float64) (float64, float64) {
    var area = length * width
    var perimeter = (length + width) * 2
    return area, perimeter
}

func main() {
    area, _ := rectPoints(10, 5)
    fmt.Printf("area is %f", area)
} // 50

2. 函数中变量的作用域

作用域:变量可以使用的范围

局部变量

一个函数内部定义的变量,就叫做局部变量 变量在哪里定义,就只能在哪个范围内使用,超出这个范围,我们认为变量就被销毁了

// 定义函数[testScope], 分析函数的作用域
func testScope(args int) {
    args = 100
    fmt.Println(args)
}

// 调用
var args int
    testScope(args)
    fmt.Println(args)
    
// 100
// nil

全局变量

一个函数外部定义的变量,就叫做全局变量 所有的函数都可以使用,而且共享这一份数据

递归函数

什么是递归函数,在一个循环体当中执行,必须有一个条件可以在满足某个条件时终止当前的循环,否则死循环 例如: 斐波那契数列

/*
    位置        值
    1        1
    2        1
    3        2
    4        3
    ..        ..
    n        func(n-1) + func(n-2)
    */

传递一个位置,返回当前位置的值

- 1.定义函数[fibonaci]实现

func fibonaci(index int64) int64 {
    if index == 1 || index == 2 {
        return 1
    } else {
        return fibonaci(index-1) + fibonaci(index-2)
    }
}
- 2.调用
//第20位置对应的值
    fmt.Println(fibonaci(2))

defer

延迟是什么

即延迟(defer)语句,延迟语句被用于执行一个函数调用,在这个函数之前,延迟语句返回

延迟函数

你可以在函数中添加多个defer语句。被函数执行到最后时,这些defer语句会按照逆序执行,最后该函数返回。特别是当你在进行一些打开资源的操作时,遇到错误需要提前返回,在返回前你需要关闭相应的资源,不然很容易造成资源泄漏等问题

  • 如果有很多调用defer,那么defer是采用后进先出模式
  • 在离开所在的方法时,执行(报错也会执行)
func reader() bool {
    file.Open("file")
    defer file.close()
    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}
// 最后才执行file.close()

示例:

package main
import "fmt"
func main() {
    a := 1
    b := 2
    defer fmt.Println(b)
    fmt.Println(a)
}
// 结果
// 1
// 2

示例:

package main
import "fmt"

func finished() {
    fmt.Println("Finished finding largest")
}

func largest(nums []int) {
    defer finished()
    fmt.Println("started finding largest")
    max := nums[0]
    for _, v := range nums {
        if v > max {
            max = v
        }
    }
    fmt.Println("largest number in", nums, "is", max)
}

func main() {
    nums := []int{1, 2, 3, 4, 5}
    largest(nums)
}

// Started finding largest
// largest number in [1 2 3 4 5] is 5
// Finished finding largest

延迟方法

延迟并不仅仅局限于函数。延迟一个方法调用也是完全合法的。

package main
import "fmt"

type person struct {
    firstName string
    lastName string
}

func (p person) fullName() {
    fmt.Printf("%s %s", p.firstName.p.lastName)
}

func main() {
    p := person {
        firstName: "xiaohe",
        lastName: "afei"
    }
    defer p.fullName()
    fmt.Printnf("Welcome")
}

// Welcome xiaohe afei

延迟参数

延迟函数的参数在执行延迟语句时被执行,而不是在执行时记得函数调用时执行

package main
import "fmt"

func printA(a int) {
    fmt.Println("value of a in deferred function", a)
}

func main() {
    a := 5
    defer printA(a)
    a = 10
    fmt.Println("value of a befored function call", a)
}
// 后进,先出
// value of a befored function call 10
// value of a in deferred function 5

堆栈的推迟

当一个函数有多个延迟调用时,它们被添加到一个堆栈中,并在last in first out(LIFO)后进先出的顺序中执行

package main
import "fmt"

func main() {
    name := "afei"
    fmt.Printf("name string %s\n", string(name))
    fmt.Printf('reversed string:")
    for _, v := range []rune(name) {
        defer fmt.Printf("%c", v)
    }
}
// name string: afei
// reversed string: AFEI

defer注意点:

  • 当外围函数中的语句正常执行完毕时,只有其中所有的延迟函数都执行完毕,外围函数才会真正的结束执行。
  • 当执行外围函数中的return语句时,只有其中所有的延迟函数都执行完毕后,外围函数才会真正返回。
  • 当外围函数中的代码引发运行恐慌时,只有其中所有的延迟函数都执行完毕后,该运行时恐慌才会真正被扩展至调用函数。