10-Go语言函数

栏目: C · 发布时间: 6年前

内容简介:+为了提升代码的可读性,我们还可以将这个大函数拆解为独立的匿名函数

函数

  • Go语言和 C语言 一样也有函数的概念, Go语言中函数除了定义格式和不用声明以外,其它方面几乎和C语言一模一样
  • 格式:
func 函数名称(形参列表)(返回值列表){
    函数体;
}
  • 无参数无返回值函数
func say()  {
    fmt.Println("Hello World!!!")
}
  • 有参数无返回值函数
func say(name string)  {
    fmt.Println("Hello ", name)
}
  • 无参数有返回值函数
func sum() int { // 只有一个返回值时,返回值列表的()可以省略
    return 1 + 1
}
  • 有参数有返回值函数
func sum(a int, b int) int {
    return a + b
}

和C语言函数差异

  • 和C语言不同的是,Go语言中可以给函数的返回值指定名称
// 给返回值指定了一个名称叫做res, return时会自动将函数体内部res作为返回值
// 其实本质就是提前定义了一个局部变量res, 在函数体中使用的res就是这个局部变量,返回的也是这个局部变量
func sum() (res int) { 
    res = 1 + 1
    return
}
  • 和C语言不同的是,Go语言中的函数允许有多个返回值函数
func calculate(a int, b int) (sum int, sub int) {
    sum = a + b
    sub = a - b
    return
}
  • 相邻同类型形参OR返回值类型可以合并, 可以将数据类型写到最后一个同类型形参OR返回值后面
// a, b都是int类型, 所以只需要在b后面添加int即可
func calculate(a, b int) (sum, sub int) {
    sum = a + b
    sub = a - b
    return
}
  • 和C语言不同的是 Go 语言中的函数不需要先声明在使用
package main
import "fmt"
func main() {
    say();
}
func say()  { // 在后面定义也可以在前面使用
    fmt.Println("Hello World!!!")
}
  • 和C语言不同的是Go语言中的函数不支持嵌套定义
func test1()  {
    func test2()  {

    }
}

值传递和引用传递

  • Go语言中 值类型 有: int系列、float系列、bool、string、数组、结构体
    • 值类型通常在栈中分配存储空间
    • 值类型作为函数参数传递, 是拷贝传递
    • 在函数体内修改值类型参数, 不会影响到函数外的值
package main
import "fmt"
func main() {
    num := 10
    change(num)
    fmt.Println(num) // 10
}
func change(num int)  {
    num = 998
}
package main
import "fmt"
func main() {
    arr := [3]int{1, 3, 5}
    change(arr)
    fmt.Println(arr) // 1, 3, 5
}
func change(arr [3]int)  {
    arr[1] = 8
}
package main
import "fmt"
type Person struct {
    name string
    age int
}
func main() {
    p := Person{"lnj", 33}
    change(p)
    fmt.Println(p.name) // lnj
}
func change(p Person)  {
    p.name = "zs"
}
  • Go语言中 引用类型 有: 指针、slice、map、channel
    • 引用类型通常在堆中分配存储空间
    • 引用类型作为函数参数传递,是引用传递
    • 在函数体内修改引用类型参数,会影响到函数外的值
package main
import "fmt"
func main() {
    num := 10
    change(#)
    fmt.Println(num) // 998
}
func change(num *int)  {
    *num = 998
}
package main
import "fmt"
func main() {
    arr := []int{1, 3, 5}
    change(arr)
    fmt.Println(arr) // 1, 8, 5
}
func change(arr []int)  {
    arr[1] = 8
}
package main
import "fmt"
func main() {
    mp := map[string]string{"name":"lnj", "age":"33"}
    change(mp)
    fmt.Println(mp["name"]) // zs
}
func change(mp map[string]string)  {
    mp["name"] = "zs"
}

匿名函数

  • 匿名函数也是函数的一种, 它的格式和普通函数一模一样,只不过没有名字而已
    • 普通函数的函数名称是固定的, 匿名函数的函数名称是系统随机的
  • 匿名函数可以定义在函数外(全局匿名函数),也可以定义在函数内(局部匿名函数), Go语言中的普通函数不能嵌套定义, 但是可以通过匿名函数来实现函数的嵌套定义
    • 全局匿名函数
    package main
    import "fmt"
    // 方式一
    var a = func()  {
      fmt.Println("hello world1")
    }
    // 方式二
    var (
        b  = func()  {
          fmt.Println("hello world2")
        }
    )
    func main() {
        a()
        b()
    }
  • 一般情况下我们很少使用全局匿名函数, 大多数情况都是使用局部匿名函数, 匿名函数可以直接调用、保存到变量、作为参数或者返回值
  • 直接调用
package main
import "fmt"
func main() {
    func(s string){
        fmt.Println(s)
    }("hello lnj")
}
  • 保存到变量
package main
import "fmt"
func main() {
    a := func(s string) {
        fmt.Println(s)
    }
    a("hello lnj")
}
  • 作为参数
package main
import "fmt"
func main() {
    test(func(s string) {
        fmt.Println(s)
    })
}
func test(f func(s string))  {
    f("hello lnj")
}
  • 作为返回值
package main
import "fmt"
func main() {
    res := test()
    res(10, 20)
}
func test() func(int, int) {
    return func(a int, b int) {
        fmt.Println(a + b)
    }
}
  • 匿名函数应用场景
    • 当某个函数只需要被调用一次时, 可以使用匿名函数
    • 需要执行一些不确定的操作时,可以使用匿名函数
package main
import "fmt"
func main() {
    // 项目经理的一天
    work(func() {
        fmt.Println("组织部门开会")
        fmt.Println("给部门员工分配今天工作任务")
        fmt.Println("检查部门员工昨天提交的代码")
        fmt.Println("... ...")
    })
    // 程序员的一天
    work(func() {
        fmt.Println("参加部门会议")
        fmt.Println("修改测试提交的BUG")
        fmt.Println("完成老大今天安排的任务")
        fmt.Println("... ...")
    })
}
// 假设我们需要编写一个函数,用于描述一个人每天上班都需要干嘛
// 职场中的人每天上班前,上班后要做的事几乎都是相同的, 但是每天上班过程中要做的事确实不确定的
// 所以此时我们可以使用匿名函数来解决, 让上班的人自己觉得自己每天上班需要干什么
func work(custom func())  {
    // 上班前
    fmt.Println("起床")
    fmt.Println("刷牙")
    fmt.Println("洗脸")
    fmt.Println("出门")
    fmt.Println("上班打卡")
    fmt.Println("开电脑")

    // 上班中
    custom()

    // 上班后
    fmt.Println("关电脑")
    fmt.Println("下班打卡")
    fmt.Println("出门")
    fmt.Println("到家")
    fmt.Println("吃饭")
    fmt.Println("睡觉")

}

+为了提升代码的可读性,我们还可以将这个大函数拆解为独立的匿名函数

func work(custom func())  {
    // 这种写法的好处是代码层次清晰,并且如果有一些变量
    // 只需要在上班前或上班后使用,还可以将这些变量隔离,不对外界造成污染
    // 上班前
    func(){
        fmt.Println("起床")
        fmt.Println("刷牙")
        fmt.Println("洗脸")
        fmt.Println("出门")
        fmt.Println("上班打卡")
        fmt.Println("开电脑")
    }()

    // 上班中
    custom()

    // 上班后
    func(){
        fmt.Println("关电脑")
        fmt.Println("下班打卡")
        fmt.Println("出门")
        fmt.Println("到家")
        fmt.Println("吃饭")
        fmt.Println("睡觉")
    }()

}
func work(custom func())  {
    // 前提条件是这个函数只在work函数中使用, 两者有较强的关联性, 否则建议定义为普通函数
    pre := func(){
        fmt.Println("起床")
        fmt.Println("刷牙")
        fmt.Println("洗脸")
        fmt.Println("出门")
        fmt.Println("上班打卡")
        fmt.Println("开电脑")
    }
    latter := func(){
        fmt.Println("关电脑")
        fmt.Println("下班打卡")
        fmt.Println("出门")
        fmt.Println("到家")
        fmt.Println("吃饭")
        fmt.Println("睡觉")
    }
    
    // 上班前
    pre()
    // 上班中
    custom()
    // 上班后
    latter()
}

闭包

  • 闭包是一个特殊的匿名函数, 它是匿名函数和相关引用环境组成的一个整体
    • 也就是说只要匿名函数中用到了外界的变量, 那么这个匿名函数就是一个闭包
    package main
    import "fmt"
    func main() {
        num := 10
        a := func() {
            num++ // 在闭包中用到了main函数中的num, 所以这个匿名函数就是一个闭包
            fmt.Println(num) // 11
        }
        a()
    }
    • 闭包中使用的变量和外界的变量是同一个变量, 所以可以闭包中可以修改外界变量
    package main
    import "fmt"
    func main() {
        num := 10
        a := func() {
            num = 6 // 在闭包中用到了main函数中的num, 所以这个匿名函数就是一个闭包
            fmt.Println(num) // 6
        }
        fmt.Println("执行闭包前", num) // 10
        a()
        fmt.Println("执行闭包后", num) // 6
    }
    • 只要闭包还在使用外界的变量, 那么外界的变量就会一直存在
    package main
    import "fmt"
    func main() {
          res := addUpper() // 执行addUpper函数,得到一个闭包
      fmt.Println(res()) // 2 
      fmt.Println(res()) // 3
      fmt.Println(res()) // 4
      fmt.Println(res()) // 5
    }
    func addUpper() func() int {
        x := 1
        return func() int {
            x++ // 匿名函数中用到了addUpper中的x,所以这是一个闭包
            return x
        }
    }

延迟调用

  • Go语言中没有提供其它面向对象语言的析构函数, 但是Go语言提供了defer语句用于实现其它面向对象语言析构函数的功能
  • defer语句常用于 释放资源解除锁定 以及 错误处理
    • 例如C语言中我们申请了一块内存空间,那么不使用时我们就必须释放这块存储空间
    • 例如C语言中我们打开了一个文件,那么我们不使用时就要关闭这个文件
    • 例如C语言中我们打开了一个数据库, 那么我们不使用时就要关闭这个数据库
    • 这一类的操作在Go语言中都可以通过defer语句来完成
  • 无论你在什么地方注册defer语句,它都会在所属函数执行完毕之后才会执行, 并且如果注册了多个defer语句,那么它们会按照 后进先出 的原则执行
    • 正是因为defer语句的这种特性, 所以在Go语言中关闭资源不用像C语言那样用完了再关闭, 我们完全可以打开的同时就关闭, 因为无论如何defer语句都会在所属函数执行完毕之后才会执行
package main
  import "fmt"
  func main() {
    defer fmt.Println("我是第一个被注册的") // 3
    fmt.Println("main函数中调用的Println") // 1
    defer fmt.Println("我是第二个被注册的") // 2
  }

init函数

  • golang里面有两个保留的函数:
    • init函数(能够应用于所有的package)
    • main函数(只能应用于package main)
    • 这两个函数在定义时不能有任何的参数和返回值
  • go程序会自动调用init()和main(),所以你 不能 在任何地方调用这两个函数
  • package main必须包含一个main函数, 但是每个package中的init函数都是可选的
  • 一个package里面可以写任意多个init函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个package中每个文件只写一个init函数
  • 单个包中代码执行顺序如下
    • main包-->常量-->全局变量-->init函数-->main函数-->Exit
package main
import  "fmt"
const constValue  = 998 // 1
var gloalVarValue int = abc() // 2
func init() { // 3
    fmt.Println("执行main包中main.go中init函数")
}
func main() { // 4
    fmt.Println("执行main包中main.go中main函数")
}
func abc() int {
    fmt.Println("执行main包中全局变量初始化")
    return 998
}
  • 多个包之间代码执行顺序如下

    10-Go语言函数
  • init函数的作用

    • init函数用于处理当前文件的初始化操作, 在使用某个文件时的一些准备工作应该放到这里

以上所述就是小编给大家介绍的《10-Go语言函数》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Designing for Emotion

Designing for Emotion

Aarron Walter / Happy Cog / 2011-10-18 / USD 18.00

Make your users fall in love with your site via the precepts packed into this brief, charming book by MailChimp user experience design lead Aarron Walter. From classic psychology to case studies, high......一起来看看 《Designing for Emotion》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试