GO语言入门4---函数

目录


函数的定义

package main // 固定
import "fmt"

// func声明函数
// MyFunc为函数名
// a, b, c int为参数和参数的类型
// int声明函数的返回类型
func MyFunc(a, b, c int) int {
    return a + b + c
}

func main() { // 大括号的位置是固定的
    sum:=MyFunc(1, 2, 3)
    fmt.Println(sum)
}

函数返回多个值

package main // 固定
import "fmt"

// func声明函数
// MyFunc为函数名
// a, b, c int为参数和参数的类型
// int声明函数的返回类型
func MyFunc() (string, int) {
    name := "zeng"
    age := 21
    return name, age
}

func main() { // 大括号的位置是固定的
    name,age:=MyFunc()
    fmt.Println(name, age)
}


可变参数函数

package main // 固定
import "fmt"

func MyFunc(first int, others ...int)  {
    for _,value := range others {
        fmt.Println(value)
    }
}

func main() { // 大括号的位置是固定的
    MyFunc(1, 2, 3, 4, 5)
}

函数参数的引用传递

如果形参不使用引用做为传递,那么在函数里面对形参所做的修改不会改变外部的参数
package main // 固定
import "fmt"

// 在函数内部修改name的值,是会改变外部参数的
func MyFunc(name *string)  {
    *name = "zeng"
}

func main() { // 大括号的位置是固定的
    name:="zengraoli"
    fmt.Println(name)
    MyFunc(&name)
    fmt.Println(name)
}

函数作为值

package main // 固定
import "fmt"

func main() { // 大括号的位置是固定的
    GetName := func() string{return "zeng"}
    fmt.Println(GetName())
}

匿名函数

匿名函数是指没有定义名字符号的函数,和一般函数最大的曲边是可在函数内部定义匿名函数,形成类型嵌套效果。
匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
package main // 固定
import "fmt"

// 闭包需要拆包才能知道他的函数意思
func GetName()  func() int{
    i:=99
    return func() int {
        return i
    }
}

func main() { // 大括号的位置是固定的
    MyName:=GetName()
    fmt.Println(MyName())
}
另外的例子
package main

import "fmt"

func Test(f func()) {
    f()
}

func RetureTest() func(int, int) int {
    return func(x int, y int) int {
        return x + y
    }
}

func TestStruct() {
    type calc struct {
        mul func(x, y int) int
    }

    x := calc {
        func(x, y int) int {
            return x * y
        },
    }

    fmt.Println(x.mul(2, 3))
}

func TestChannel() {
    c := make(chan func(int, int) int, 2)

    c <- func(x int, y int) int {
        return x + y
    }

    fmt.Println((<-c)(1, 2))
}

func main() {
    // 直接执行匿名函数
    func(s string) {
        fmt.Println(s)
    }("zengraoli1")

    // 赋值给变量
    add1 := func(x, y int) int {
        return x + y
    }
    fmt.Println(add1(1, 2))

    // 作为参数
    Test(func() {
        fmt.Println("zengraoli2")
    })

    // 作为返回值
    add3 := RetureTest()
    fmt.Println(add3(1, 88))

    // 普通函数和匿名函数都可以作为结构体,或经通道传递
    TestStruct()
    TestChannel()
}

延迟函数defer

语法上,一个defer语句就是一个普通的函数或方法调用,在调用之前加上关键字defer。defer不影响普通的return语句,但即便执行return语句,defer也会被执行。Defer语句没有限制使用次数,执行的时候以调用defer语句顺序的倒序进行。

示例如下,首先会输出return,然后再输出close
package main // 固定
import (
    "os"
    "fmt"
)

func MyClose(file *os.File) {
    file.Close()
    fmt.Println("MyClose...")
}

func Test() {
    file,err := os.OpenFile("output.txt", os.O_CREATE|os.O_APPEND, os.ModePerm|os.ModeTemporary)
    if err != nil {
        fmt.Println(err)
    }

    // 延迟关闭文件
    defer MyClose(file)
    out := ""
    for index := 0; index < 10; index++ {
        out = fmt.Sprintf("%d\r\n", index)
        file.Write([]byte(out))
    }
    fmt.Println("return...")
}

func main() { // 大括号的位置是固定的
    Test()
}
如果在return前出现错误,程序被中断了,也还是能执行defer(Go出现中断使用panic)
package main // 固定
import (
    "os"
    "fmt"
)

func MyClose(file *os.File) {
    file.Close()
    fmt.Println("MyClose...")
}

func Test() {
    file,err := os.OpenFile("output.txt", os.O_CREATE|os.O_APPEND, os.ModePerm|os.ModeTemporary)
    if err != nil {
        fmt.Println(err)
    }

    // 延迟关闭文件
    defer MyClose(file)
    out := ""
    for index := 0; index < 10; index++ {
        out = fmt.Sprintf("%d\r\n", index)
        file.Write([]byte(out))
        if index == 3 {
            panic("抛出异常后,程序就要终止了.")
        }
    }
    fmt.Println("return...")
}

func main() { // 大括号的位置是固定的
    Test()
}

可以看到正常的return输出已经没有了,但依然还能看到Close的输出,说明defer还是会继续执行

还有一个其他作用,能够利用defer来做异常捕获,参看
https://blog.csdn.net/qq_27682041/article/details/78786689


错误处理

Go的错误处理方式比较复古,返回一个error,比如下面的
package main

import (
    "fmt"
    "errors"
)

func div(x, y int) (int, error) {
    if y == 0 {
        return 0, errors.New("division by zeor")
    }
    return x / y, nil
}

func main() {
    z, err := div(5, 0)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(z)
}
还可以自定义错误类型,以容纳更多上下文状态信息,还可以基于类型做出判断
package main

import "fmt"

type DivError struct {
    x, y int
}

func (DivError) Error() string  {
    return "division by zeor"
}

func div(x, y int) (int, error) {
    if y == 0 {
        return 0, DivError{x, y}
    }
    return x / y, nil
}

func main() {
    z, err := div(5, 0)
    if err != nil {
        switch e := err.(type) {
        case DivError:
            fmt.Println(e, e.x, e.y)
        default:
            fmt.Println(e)
        }
    }
    fmt.Println(z)
}

*panic和recover
panic和recover的用法更接近于try/catch结构,除非是不可恢复性、导致系统无法正常工作的错误,否则不建议使用panic

使用可以参考
https://www.cnblogs.com/sunshine-anycall/p/4746066.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值