go语言 函数和包
一、函数
在Go语言中,函数是执行特定任务的自包含代码块。
1.函数的定义
函数通过func
关键字定义,格式如下:
func 函数名(形参 形参类型, 形参 形参类型) 返回值类型 {函数体return 返回值 }
2.基础函数类型
- 无参数无返回值
- 单个参数,无返回值
- 多个相同类型参数,无返回值
- 多个不同类型参数,无返回值
- 多个参数,一个返回值
- 多个参数,多个返回值
package mainimport "fmt"func main() {demo01()//demo02("d") // 类型不匹配demo02(2)demo03(1, 2)demo04(1, "A")var res = demo05(1, 2)fmt.Println("a+b:", res)var res1, res2 = demo06(1, 1)fmt.Println(res1, res2) }// 无参数无返回值 func demo01() {fmt.Println("hello world") }// 单个参数,无返回值 func demo02(a int) {fmt.Println("a:", a) }// 多个相同类型参数,无返回值 func demo03(a, b int) {fmt.Println("a+b:", a+b) }// 多个不同类型参数,无返回值 func demo04(a int, b string) {fmt.Println("a:", a)fmt.Println("b:", b) }// 多个参数,一个返回值 func demo05(a, b int) int {return a + b }// 多个参数,多个返回值 func demo06(a, b int) (int, bool) {if a+b > 3 {return a + b, true} else {return a * b, false} }
3.特殊函数类型
- 匿名函数:
test06
展示了如何在Go中定义匿名函数,即没有函数名的函数。 - 函数作为一等公民:
f
变量可以存储函数,test11
返回一个函数作为其结果。 - 命名返回值:
test10
展示了如何使用命名返回值,这有助于提高代码的可读性。 - 闭包:
test12
是一个闭包示例,它捕获并使用外部作用域的变量。 - 函数作为参数:
test14
接受一个函数作为参数,并在函数体内调用它。 - 类型重命名:
MyFunc
是func(string) (int, int)
类型的别名。
package mainimport "fmt"func main() {demo01()// 函数作为一等公民var demo02 = func(a, b int) int {return a + b}var res = demo02(15, 16)fmt.Println(res)var res1, res2 = demo03(16, 17)fmt.Println(res1, res2)// 闭包var ff = demo04(15)ff()// 函数作为参数var f1 = func(a int) {fmt.Println(a)}demo05(15, f1)// 类型重命名type StringProcessor func(string) stringprocessor := StringProcessor(func(input string) string {return "Processed: " + input})result := processor("Input")fmt.Println(result)}// 匿名函数 func demo01() {fmt.Println("demo01--start")// 定义匿名函数并立即执行func() {fmt.Println("demo01--inner")}()fmt.Println("demo01--end") }// 命名返回值 func demo03(a, b int) (sum int, flag bool) {sum = a + bflag = true//return sum, flag // 可以指定return // 也可以不在指定 }// 闭包 func demo04(x int) func() {x = 666f := func() {fmt.Println("我是内部函数", x)}return f }// 函数作为参数 func demo05(a int, f func(i int)) {f(a) }
4.装饰器函数
-
Go语言虽然没有像一些其他语言(例如Python)那样的装饰器语法,但是可以通过闭包来实现类似的功能。
-
装饰器通常用于在不修改原始函数代码的情况下增加函数的功能。
-
示例
package mainimport ("fmt""time" )// 普通函数 func sayHello(name string) string {time.Sleep(time.Second) // 延迟1秒return "Hello " + name }// 自定义装饰器,计时功能 func timeTrack(fn func(string) string) func(string) string {return func(name string) string {startTime := time.Now() // 记录开始时间result := fn(name) // 调用原始函数elapsedTime := time.Since(startTime) // 计算经过时间fmt.Printf("耗时: %s \n", elapsedTime)return result} } func main() {// 使用装饰器增强原始函数enhanceSayHello := timeTrack(sayHello)helloMessage := enhanceSayHello("world")fmt.Println(helloMessage) }
二、包
在Go语言中,包(package)是组织源代码的基本单位,它有助于代码的可重用性和可读性
1.包规则
- 导出规则:如果一个函数、变量或类型的名称以大写字母开头,它就是导出的(exported),这意味着它可以在包外部被访问和使用。如果以小写字母开头,则它在包外部是不可见的。
- 包名一致性:在同一个文件夹下的所有Go源文件应该属于同一个包,并且包名通常建议与文件夹名相同。这是为了保持代码的清晰和易于理解。
- 包内部可见性:在同一个包内的所有源文件共享相同的包级作用域,这意味着这些文件中的所有变量、函数和类型都像是在同一个文件中一样可见。
- 使用包:要使用其他包中的导出成员,需要导入对应的包,并通过包名来引用它们。
- 导入包:使用
import
关键字来导入包。导入时,通常使用包的全路径名,例如import "demo/common"
。 - 导入并重命名包:如果包名冲突或者为了方便引用,可以在导入时为包指定一个新的名称,例如
import cv1 "demo/common/v1"
。 - 一次导入多个包:可以通过一对花括号来一次导入多个包,这样可以保持代码的整洁。
2.示例
-
目录结构
-
demo/ ├── common/ │ ├── v1/ # v1 是 common 包的一个子目录,表示版本1 │ │ └── demo01.go # demo01.go 是 common 包 v1 版本的实现文件 │ ├── demo02.go # demo02.go 是 common 包的一部分,不在任何子目录中 │ └── demo01.go # 这是 common 包的另一个实现文件,可能与 v1 版本不同 └── main.go # main.go 是 main 包的入口文件,通常包含 main 函数 └── go.mod # go.mod 是 Go 模块的配置文件,记录模块的依赖关系
-
-
文件内容
-
// main.go package main// 导入标准库中的fmt包 import "fmt"// 一次导入多个包 import ("demo/common"cv1 "demo/common/v1" // // 导入包并重命名 )func main() {// 使用fmt包的Println函数fmt.Println("Hello, world!")res1 := common.Add(1, 2)fmt.Println(res1)res2 := cv1.Mul(4, 5) // 使用重命名的包fmt.Println(res2) }
-
// common/demo01.gopackage common func Add(a, b int) int {return a + b }
-
// common/demo02.gopackage common func Addd(a, b int) int {return Add(a, b) + b }
-
// common/v1/demo01.gopackage v1 func Mul(a, b int) int {return a * b }
-