[Go语言快速上手]函数和包
目录
一、Go中的函数
函数声明
多个返回值
可变参数
匿名函数
值传递和地址传递
函数执行顺序(init函数)
二、Go中的包
基本语法
主要包(main package)
导入其他包
包的作用域
包的使用
包名别名
小结
一、Go中的函数
Go中的函数与其他函数中功能大差不差,只是格式不同,当然也更加简便,从中可以看到其他语言的影子,但是开发效率会高上不少。
函数声明
- 函数签名:函数的声明包括函数名、参数列表和返回类型。
- 参数:可以在函数定义中指定参数的名字和类型。
- 返回值:可以指定函数返回的类型。如果函数不需要返回任何值,可以使用
()
表示无返回值。
一个简单的Go函数定义如下:
package main
import "fmt"
// 定义一个名为 add 的函数,接受两个 int 参数,返回一个 int 结果
func add(a int, b int) int {
return a + b
}
func main() {
// 调用 add 函数
result := add(2, 3)
fmt.Println("结果是:", result)
}
多个返回值
我们的返回值列表也可以设置多返回值,这个C++中可能就要设置自定义数据类型或者模板来实现,而Go提供了很便捷的方法,直接定义返回值列表返回即可
func divide(a int, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果是:", result)
}
}
可变参数
如果你想要传递可变数量的参数给一个函数,可以使用 ...
操作符
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
result := sum(1, 2, 3, 4, 5)
fmt.Println("总和是:", result)
}
匿名函数
你也可以定义匿名函数,并将其赋值给一个变量或立即调用:
func main() {
sum := func(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
result := sum(1, 2, 3, 4, 5)
fmt.Println("总和是:", result)
}
我们来看这一种情况,将函数赋值给一个变量,这个变量就是一个函数,和我们之前学习的函数指针非常像,回调函数的场景应用非常多
func test(args ...int) {
//函数内部处理可变参数,将可变参数当作切片来处理
for i := 0; i < len(args); i++ {
fmt.Println(args[i])
}
}
func test2(num1 int, num2 int, funct func(args ...int)) {
funct(num1, num2)
}
func main() {
//var a = 10
//var b = 20
//exchange(&a, &b)
//fmt.Println(a)
//fmt.Println(b)
test(1, 2, 3, 4, 5, 6, 7, 8, 6, 55)
c := test
fmt.Printf("c:%T,test:%T\n", c, test)
c(1, 2, 3, 5, 6, 7, 8)
test2(1, 2, test) //test和C是完全一样的
test2(1, 2, c)
}
可以看到c和test的类型没有任何区别
值传递和地址传递
在C语言中我们直到形参的改变不会引起实参的改变,所以我们需要传递实参的地址
package main
import "fmt"
func exchange(num1 *int, num2 *int) {
var tmp int = *num1
*num1 = *num2
*num2 = tmp
}
func test(args ...int) {
//函数内部处理可变参数,将可变参数当作切片来处理
for i := 0; i < len(args); i++ {
fmt.Println(args[i])
}
}
func test2(num1 int, num2 int, funct func(args ...int)) {
funct(num1, num2)
}
func main() {
var a = 10
var b = 20
exchange(&a, &b)
fmt.Println(a)
fmt.Println(b)
test(1, 2, 3, 4, 5, 6, 7, 8, 6, 55)
//c := test
fmt.Printf("c:%T,test:%T", c, test)
c(1, 2, 3, 5, 6, 7, 8)
//test2(1, 2, test)
//test2(1, 2, c)
}
函数执行顺序(init函数)
全局变量初始化:全局变量的初始化按其声明顺序进行。
包级别的
init
函数:每个包中的init
函数按包的依赖顺序执行。
main
函数:一旦所有初始化完成,程序进入main
包的main
函数。
下面是一个综合示例,展示了全局变量初始化、包级别的 init
函数和 main
函数的执行顺序
// pkg1/init.go
package pkg1
var x = initX()
func initX() int {
println("初始化 pkg1.x")
return 10
}
func init() {
println("pkg1 的 init 函数")
}
// pkg2/init.go
package pkg2
var y = initY()
func initY() int {
println("初始化 pkg2.y")
return 20
}
func init() {
println("pkg2 的 init 函数")
}
// main/main.go
package main
import (
"pkg1"
"pkg2"
)
func main() {
println("main 函数开始")
println("pkg1.x 的值:", pkg1.x)
println("pkg2.y 的值:", pkg2.y)
}
输出是
初始化 pkg1.x
pkg1 的 init 函数
初始化 pkg2.y
pkg2 的 init 函数
main 函数开始
pkg1.x 的值: 10
pkg2.y 的值: 20
二、Go中的包
在 Go 语言中,包(package)是一个重要的概念,用于组织和复用代码。通过使用包,你可以将相关的函数、类型、变量等组织在一起,从而提高代码的可维护性和可读性。
基本语法
每个 Go 文件必须属于一个包。包的声明位于文件的顶部:
package mypackage
其中 mypackage
是包的名称。通常,包名会反映其功能或用途(一般建议包名和文件夹名称相同)
主要包(main package)
一个特殊的包是 main
包,它是程序的入口点。当编译和运行一个 Go 程序时,默认情况下会编译 main
包。main
包中的 main
函数是程序执行的起点:
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
导入其他包
你可以通过 import
语句来导入其他包。导入语句通常位于包声明之后,但在任何其他代码之前
如果导入多个包,可以使用这种写法更为便捷
import (
"fmt" // 标准库包
"mypackage" // 自定义包
)
包的作用域
在 Go 中,包内的标识符(如变量、函数、类型等)默认具有包级作用域,这意味着它们只能在同一包内访问。为了使一个标识符在其他包中也能访问,需要将其首字母大写
package common
// 大写的标识符在其他包中可访问
func Add(a int, b int) int {
return a + b
}
// 小写的标识符只在当前包中可访问
func add(a int, b int) int {
return a + b
}
包的使用
我们来看一下下图,如果将所有函数都写在一个文件里那么会很难阅读,同时模块划分也会很混乱,所以我们可以把一些工具函数写在其他包中,在需要使用的地方导入包即可。
我们可以使用这样一个简单的结构来测试
在main中调用common中的Add和db中的Getconn
package db
func Getconn() {
println("数据库连接")
println("dbutil函数执行")
}
package aaa
func Add(a int, b int) int {
println("common_________")
return a + b
}
main.go
package main
import (
"fmt"
"gocode/test_10_2/common"
"gocode/test_10_2/db"
)
func main() {
fmt.Println("main函数执行")
db.Getconn()
var c int = aaa.Add(1, 5)
println(c)
}
运行输出如下
那同名函数会冲突吗
我们在db中也定义一个Add调用,其实也不会冲突,因为需要使用导入的包名作为前缀来调用函数。//在 main 函数中,我们使用 aaa.Add 来调用 Add 函数。这里 aaa 是包名,Add 是函数名。
包名别名
如果导入的包名较长,或者为了避免与其他包名冲突,可以给包起一个别名,比如下面的例子我们就使用了test来当作包名,但是使用了test后就不能再使用原来的包名了
package main import ( "fmt" test "gocode/test_10_2/common" "gocode/test_10_2/db" ) func main() { fmt.Println("main函数执行") db.Getconn() var c int = test.Add(1, 5) println(c) var d int = db.Add(3, 4) println(d) }
小结
以上就是Go中一些函数和包的简单使用,在实际应用场景中可能更多的用法,就需要我们在这些基础上进行操作。函数是 Go 语言中非常灵活的构造,可以用来实现各种复杂的逻辑。合理地组织和使用包,可以使 Go 程序更加模块化和易于维护。确保遵循 Go 的最佳实践,如使用简洁的包名、导出必要的标识符等,可以使代码更加健壮和易用。