Go 语言(也称为 Golang)的函数是执行特定任务的代码块。它们允许你重用代码,让程序更加模块化和易于维护。在 Go 中,函数可以接收参数(输入值)并返回结果(输出值)。下面详细解释 Go 语言中的函数:
函数定义
函数通过 func
关键字定义。基本结构如下:
func functionName(parameterList) (resultTypeList) { | |
// 函数体 | |
} |
functionName
是函数的名称,它遵循 Go 的标识符命名规则(字母、数字、下划线,不能以数字开头)。parameterList
是传递给函数的参数列表,它是可选的。参数之间用逗号分隔。resultTypeList
是函数返回值的类型列表,也是可选的。如果函数不返回任何值,则可以省略返回值类型。如果有多个返回值,它们之间用逗号分隔。- 函数体包含了执行任务的代码。
Go语言有自己的内置函数
1. 错误处理
panic 和 recover:panic 用于中断当前函数的执行,并开始逐层向上执行函数中的延迟(deferred)函数直到程序崩溃。recover 是一个内置的函数,它用来阻止 panic 的继续传播,并捕获到 panic 的值。
package main
import "fmt"
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in main", r)
}
}()
fmt.Println("Calling myFunction")
myFunction()
fmt.Println("Returned normally from myFunction")
}
func myFunction() {
panic("A problem!")
}
2. 类型断言
类型断言:用于访问接口值底层的具体值。
package main
import (
"fmt"
)
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
// 如果不确定类型,可以使用类型断言的第二种形式,避免panic
s, ok := i.(string)
if ok {
fmt.Println(s)
} else {
fmt.Println("i is not a string")
}
}
3. 数学运算
len 和 cap:len 返回集合的长度(如字符串、数组、切片、映射或通道的元素个数),cap 返回切片的容量。
package main
import "fmt"
func main() {
s := "hello"
fmt.Println("len(s):", len(s))
slice := []int{1, 2, 3, 4, 5}
fmt.Println("len(slice):", len(slice))
fmt.Println("cap(slice):", cap(slice))
}
4. 闭包和延迟函数
defer:延迟函数的执行直到包含它的函数即将返回。
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
5. 集合操作
append:用于向切片追加元素,并返回新切片的引用。
package main
import "fmt"
func main() {
s := []int{2, 3, 5}
s = append(s, 7)
s = append(s, 2, 13)
fmt.Println(s)
}
6. 复制和比较
copy:用于将切片(slice)、数组(array)或字符串(string)的元素从一个复制到另一个。
package main
import "fmt"
func main() {
src := []int{2, 3, 4, 5, 6, 7}
dst := make([]int, 3)
copied := copy(dst, src)
fmt.Println(copied, dst)
}
7. 字符串处理
字符串操作:Go 语言对字符串的处理是直接的,比如使用 + 连接字符串,使用 len 获取字符串长度等。
package main
import "fmt"
func main() {
str := "hello"
fmt.Println(len(str))
newStr := str + ", world!"
fmt.Println(newStr)
}
函数案例:
package main
import(
"fmt"
)
// 定义一个函数,计算并返回整数列表中所有偶数的平方和
// 参数:numbers []int - 一个整数切片
// 返回值:int - 所有偶数的平方和
func sumOfEvenSquares(numbers []int) int {
sum := 0 // 局部变量,用于累加偶数的平方和
for _, number := range numbers { // 使用range遍历切片
if number%2 == 0 { // 判断是否为偶数
sum += number * number // 累加偶数的平方
}
}
return sum // 返回累加的结果
}
func main() {
// 定义一个整数切片
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 调用函数,并将结果存储在变量result中
result := sumOfEvenSquares(numbers)
// 使用fmt.Println打印结果
fmt.Println("The sum of squares of even numbers is:", result)
}
函数包
函数包作用很大,比如:
1. 代码重用性
函数包允许开发者将一系列相关的函数、类、变量等组织在一起,形成一个独立的模块。当这些函数、类等在多个地方被重复使用时,通过引入函数包,可以极大地提高代码的重用性,减少代码的冗余,使代码更加简洁、易于维护。
2. 项目管理
随着项目规模的扩大,项目中的文件数量会急剧增加。函数包通过提供结构化的代码组织方式,帮助开发者更好地管理项目。通过将具有相似功能的代码组织在同一个包中,开发者可以更容易地理解和维护项目结构,提高开发效率。
3. 命名空间管理
在大型项目中,不同模块之间可能存在函数、变量名冲突的问题。函数包通过提供命名空间的功能,有效地解决了这一问题。每个包内部的函数、变量等都是相对独立的,不会与其他包中的同名元素产生冲突。这样,开发者就可以更加自由地命名函数、变量等,而无需担心命名冲突的问题。
4. 访问控制
函数包还提供了访问控制的功能。通过合理设置包的访问权限,开发者可以控制哪些函数、变量等可以被外部访问,哪些只能被包内部访问。这有助于保护包内部的敏感信息,防止外部代码随意修改包内部的状态。
5. 依赖管理
在复杂的项目中,不同模块之间可能存在相互依赖的关系。函数包通过清晰地定义模块之间的依赖关系,帮助开发者更好地管理项目依赖。当需要更新或替换某个模块时,开发者可以更容易地找到所有依赖该模块的代码,并进行相应的修改。
6. 并行编程
在函数式编程中,函数包还可以帮助实现并行编程。由于函数式编程语言通常具有并行执行的能力,通过将可并行化的任务封装在函数包中,并利用多核处理器的优势,可以显著提高程序的执行效率。
包的基本介绍:
包的本质实际上就是创建不同的文件夹,来存放程序文件。go 的每一个文件都是属于一个包的,也就是说 go 是以包的形式来管理文件和项目目录结构的
案例:
创建两个文件夹一个main 一个demo,分别在其中创建main.go和demo.go
demo.go的内容:
package dem
import "fmt"
var A int = 100
//函数首字母大写才能跨程序调用
func B(n1 float64, n2 float64, n3 byte) float64 {
var n4 float64
switch n3 {
case '+':
n4 = n1 + n2
case '-':
n4 = n1 - n2
case '*':
n4 = n1 * n2
case '/':
n4 = n1 / n2
default:
fmt.Println("符号错误")
}
return n4
}
main.go调用demo.go
package main
import (
"Goproject/bao/demo"
"fmt"
)
func main() {
fmt.Println("demo.go n4=", demo.A)
var n1 = 9.8
var n2 = 8.9
var n3 byte = '+'
result := demo.B(n1, n2, n3)
fmt.Printf("result=%.1f\n", result)
}