Golang 函数、包

 

一、函数 

 

fun 方法名称(形参列表) 返回值列表 {
}

 

二、包

包的基本概念

go的每一个文件都是属于包的,也就是说go是以包的形式来管理文件和项目目录结构。

包的作用

1)区分相同名字的函数、变量等表示符。

2)当程序文件很多时,可以很好的管理项目

3)控制函数、变量等访问范围,即作用域

包的打包和引入

打包基本语法

package “包名”

引入包的基本语法

import “包的路径”

注意:包中的方法名称开头字母要大写,否则即使引入包也访问不了方法,因为小写的方法名称表示“私有方法”。

第一步:创建一个文件,并写函数。在utils文件夹下创建一个utils.go文件(包),并编写 Cal方法。

package utils
import (
    "fmt"
)
//为了让其他包的文件使用Cal函数,需要将"C"大写,类似于其他语言的“public”
func Cal(n1 float64,n2 float64,operator byte) float64{
    var res float64
    switch operator {
    case '+':
        res = n1 + n2
    case '-':
        res = n1 - n2
    case '*':
        res = n1 * n2
    case '/':
        res = n1 / n2
    default:
        fmt.Println("操作符号错误...")
        
    }
    return res
}

第二步:main.go文件中引入包

注意:默认引入路径是从"src"开始,即"src"是可以不用写

package main

import (
    "fmt"
    "go_code/fordemo/utils"
)

第三步:调用方法

注意:调用格式为:包名.方法名(参数)

package main

import (
    "fmt"
    "go_code/chapter04/fordemo/utils"
)
func main(){

    var n1 float64 = 1.2
    var n2 float64 = 2.3
    var operator byte = '+'
    result := utils.Cal(n1,n2,operator)
    fmt.Println("result = ",result)

}

 三、init函数(初始化)

基本介绍

每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被go运行框架调用,也就是说init会在main函数前被调用。

package main

import (
    "fmt"
)
//init函数,通常可以在init函数中完成初始化工作
func init()  {
    fmt.Println("init()...")
}
func main(){
    fmt.Println("main()...")
}

init的注意事项和细节

1)如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程是全局变量定义->init函数->mian函数

package main

import (
    "fmt"
)

//定义一个全局变量
var age =test()

//第一个执行
//此函数用于测试 全局变量age的执行顺序
func test() int {
    fmt.Println("test()")
    return 90
}
//第二个执行
//init函数,通常可以在init函数中完成初始化工作
func init() {
    fmt.Println("init()...")
}
//第三个执行
func main() {
    fmt.Println("main()...age = ",age)
}

2)init函数最主要的作用,就是完成一些初始化的工作

 四、匿名函数

介绍

Go支持匿名函数,如果我们某个函数只是希望使用一次,可以考虑使用匿名函数,匿名函数也可以实现多次调用。

匿名函数使用方式1(项目开发中常用

在定义匿名函数时就直接调用

package main

import (
    "fmt"
)

func main() {

    //在定义匿名函数时就直接调用
    res1 := func(n1 int, n2 int) int {
        return n1 + n2
    }(10, 20)

    fmt.Println("res1 = ", res1)
}

匿名函数使用方式2

将匿名函数赋给一个变量(函数变量),在通过该变量来调用匿名函数

 

package main

import (
    "fmt"
)

func main() {

    //将匿名函数func(n1 int,n2 int) int 赋给a变量
    //则a的数据类型就是函数类型,此时,我们可以通过a完成调用
    a := func(n1 int,n2 int) int {
        return n1 - n2
    }
    rest2 := a(10,30)
    fmt.Println("res2 = ",rest2)
    rest3 := a(90,30)
    fmt.Println("res3 = ",rest3)

}

全局匿名函数

如果将匿名函数赋给一个全局变量,那么这个匿名函数,就成为一个全局函数,可以在程序有效。

package main

import (
    "fmt"
)
var (
    //fun1 就是一个全局匿名函数
    Fun1 = func (n1 int,n2 int) int {
        return n1 * n2
    }
)

func main() {


    //全局匿名函数的使用
    res4 := Fun1(4,9)
    fmt.Println("rest4 = ",res4)

}

五、闭包

介绍

闭包就是一个函数和与其关联的引用环境组合的一个整体(实体)

package main
import (
    "fmt"
)
//累加器
func AddUpper() func (int) int {
    var n int = 10
    return func (x int) int {
        n = n + x
        return n
    }
}

func main(){
    //使用前面的代码
    f := AddUpper()
    fmt.Println(f(1)) //结果是 11
    fmt.Println(f(2)) //结果是 13
    fmt.Println(f(3)) //结果是 16

}

对上面代码的说明和总结

1)AddUpper 是一个函数,返回的数据类型是 fun(int) int

2) 闭包的说明

 

 返回的是一个匿名函数,但是这个匿名函数引用到函数外的n,因此这个匿名函数就和n行成一个整体,构成闭包。

3)可以这样理解:闭包是一个类,函数是操作,n是字段。函数和它使用到的n构成一个闭包。

4)当我们反复调用f函数时,因此n是初始化一次,因此每调用一次就进行累计。

5)闭包的关键就是要分析出返回的函数它使用到哪些变量,因为函数和它引用到的变量共同构成闭包。

六、defer语句

在函数中,程序员经常需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,go的设计者提供defer(延迟机制)。

defer介绍

package main

import (
    "fmt"
)

func sum(n1 int, n2 int) int {
    //当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)
    //当函数执行完毕后,在从defer栈,按照先入后出的方式出栈执行。
    defer fmt.Println("ok1 n1 = ", n1) //3.ok1 n1 = 10
    defer fmt.Println("ok2 n2 = ", n2)  //2.ok2 n2 = 20

    res := n1 + n2
    fmt.Println("ok3 res = ", res) // 1. ok3 = 30
    return res
}
func main() {
    res := sum(10, 20)
    fmt.Println("res = ", res) //4.res = 30
}

defer的细节说明

1)当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈(暂且叫做defer栈)中,然后继续执行函数下一个语句。

2)当函数执行完毕后,在从defer栈中,依次从栈顶取出语句执行。

3)在defer将语句放入到栈时,也会将相关的值拷贝同时入栈。

package main

import (
    "fmt"
)

func sum(n1 int, n2 int) int {
    //当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)
    //当函数执行完毕后,在从defer栈,按照先入后出的方式出栈执行。
    defer fmt.Println("ok1 n1 = ", n1) //3.ok1 n1 = 10(将值也放入栈中)
    defer fmt.Println("ok2 n2 = ", n2)  //2.ok2 n2 = 20

    res := n1 + n2 //30
    n1++ //11
    fmt.Println("ok3 res = ", res,"n1 = ",n1) // 1. ok3 res = 30  n1 = 11
    return res
}
func main() {
    res := sum(10, 20)
    fmt.Println("res = ", res) //4.res = 30
}

 

defer的最佳实践

defer最主要的价值在,当函数执行完毕后,可以及时的释放函数创建的资源。

 

posted @ 2021-05-18 20:47  创客未来  阅读(117)  评论(0编辑  收藏  举报