Go 函数与方法
函数基础
函数定义语法
func functionName(parameter1 type1, parameter2 type2) returnType {
// 函数体
return value
}
基本函数示例
package main
import "fmt"
// 无参数无返回值
func sayHello() {
fmt.Println("Hello, World!")
}
// 有参数无返回值
func greet(name string) {
fmt.Printf("Hello, %s!\n", name)
}
// 有参数有返回值
func add(a, b int) int {
return a + b
}
// 多个参数相同类型
func multiply(a, b, c int) int {
return a * b * c
}
func main() {
sayHello()
greet("Go语言")
result := add(3, 5)
fmt.Printf("3 + 5 = %d\n", result)
product := multiply(2, 3, 4)
fmt.Printf("2 * 3 * 4 = %d\n", product)
}
多返回值
基本多返回值
package main
import (
"fmt"
"errors"
)
// 返回两个值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// 返回多个相同类型的值
func getNameAndAge() (string, int) {
return "张三", 25
}
// 命名返回值
func calculate(a, b int) (sum, product, difference int) {
sum = a + b
product = a * b
difference = a - b
return // 自动返回命名的返回值
}
func main() {
// 接收多个返回值
result, err := divide(10, 3)
if err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Printf("结果: %.2f\n", result)
}
// 忽略某个返回值
name, _ := getNameAndAge()
fmt.Printf("姓名: %s\n", name)
// 命名返回值
s, p, d := calculate(10, 3)
fmt.Printf("和: %d, 积: %d, 差: %d\n", s, p, d)
}
可变参数
可变参数函数
package main
import "fmt"
// 可变参数函数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// 混合参数
func greetAll(greeting string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!\n", greeting, name)
}
}
// 传递切片给可变参数
func printNumbers(numbers ...int) {
for i, num := range numbers {
fmt.Printf("numbers[%d] = %d\n", i, num)
}
}
func main() {
// 调用可变参数函数
fmt.Printf("sum() = %d\n", sum())
fmt.Printf("sum(1) = %d\n", sum(1))
fmt.Printf("sum(1, 2, 3) = %d\n", sum(1, 2, 3))
fmt.Printf("sum(1, 2, 3, 4, 5) = %d\n", sum(1, 2, 3, 4, 5))
// 混合参数
greetAll("Hello", "Alice", "Bob", "Charlie")
// 传递切片
numbers := []int{1, 2, 3, 4, 5}
printNumbers(numbers...) // 展开切片
}
函数作为值
函数类型
package main
import "fmt"
// 定义函数类型
type Operation func(int, int) int
// 实现不同的操作函数
func add(a, b int) int {
return a + b
}
func subtract(a, b int) int {
return a - b
}
func multiply(a, b int) int {
return a * b
}
// 接受函数作为参数
func calculate(a, b int, op Operation) int {
return op(a, b)
}
// 返回函数
func getOperation(operator string) Operation {
switch operator {
case "+":
return add
case "-":
return subtract
case "*":
return multiply
default:
return nil
}
}
func main() {
// 函数作为变量
var op Operation = add
result := op(3, 5)
fmt.Printf("3 + 5 = %d\n", result)
// 函数作为参数
result = calculate(10, 3, subtract)
fmt.Printf("10 - 3 = %d\n", result)
// 获取函数
multiplyOp := getOperation("*")
if multiplyOp != nil {
result = multiplyOp(4, 6)
fmt.Printf("4 * 6 = %d\n", result)
}
}
匿名函数和闭包
匿名函数
package main
import "fmt"
func main() {
// 匿名函数直接调用
result := func(a, b int) int {
return a + b
}(3, 5)
fmt.Printf("匿名函数结果: %d\n", result)
// 匿名函数赋值给变量
square := func(x int) int {
return x * x
}
fmt.Printf("5的平方: %d\n", square(5))
// 匿名函数作为参数
numbers := []int{1, 2, 3, 4, 5}
processNumbers(numbers, func(x int) int {
return x * 2
})
}
func processNumbers(numbers []int, processor func(int) int) {
for _, num := range numbers {
result := processor(num)
fmt.Printf("处理 %d 得到 %d\n", num, result)
}
}
闭包
package main
import "fmt"
// 返回闭包函数
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// 闭包捕获外部变量
func multiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
// 闭包修改外部变量
func accumulator() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
// 计数器闭包
c1 := counter()
c2 := counter()
fmt.Printf("c1: %d\n", c1()) // 1
fmt.Printf("c1: %d\n", c1()) // 2
fmt.Printf("c2: %d\n", c2()) // 1
fmt.Printf("c1: %d\n", c1()) // 3
// 乘法器闭包
double := multiplier(2)
triple := multiplier(3)
fmt.Printf("double(5) = %d\n", double(5)) // 10
fmt.Printf("triple(5) = %d\n", triple(5)) // 15
// 累加器闭包
acc := accumulator()
fmt.Printf("acc(1) = %d\n", acc(1)) // 1
fmt.Printf("acc(2) = %d\n", acc(2)) // 3
fmt.Printf("acc(3) = %d\n", acc(3)) // 6
}
方法
方法定义
package main
import (
"fmt"
"math"
)
// 定义结构体
type Circle struct {
Radius float64
}
type Rectangle struct {
Width, Height float64
}
// 为Circle定义方法
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// 为Rectangle定义方法
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func main() {
circle := Circle{Radius: 5}
rectangle := Rectangle{Width: 4, Height: 6}
fmt.Printf("圆形面积: %.2f\n", circle.Area())
fmt.Printf("圆形周长: %.2f\n", circle.Perimeter())
fmt.Printf("矩形面积: %.2f\n", rectangle.Area())
fmt.Printf("矩形周长: %.2f\n", rectangle.Perimeter())
}
指针接收者 vs 值接收者
package main
import "fmt"
type Counter struct {
count int
}
// 值接收者方法(不能修改原始值)
func (c Counter) GetCount() int {
return c.count
}
func (c Counter) IncrementValue() {
c.count++ // 只修改副本
}
// 指针接收者方法(可以修改原始值)
func (c *Counter) IncrementPointer() {
c.count++
}
func (c *Counter) Reset() {
c.count = 0
}
func main() {
counter := Counter{count: 0}
fmt.Printf("初始值: %d\n", counter.GetCount())
// 值接收者方法不会修改原始值
counter.IncrementValue()
fmt.Printf("值接收者后: %d\n", counter.GetCount()) // 仍然是0
// 指针接收者方法会修改原始值
counter.IncrementPointer()
fmt.Printf("指针接收者后: %d\n", counter.GetCount()) // 变成1
counter.IncrementPointer()
counter.IncrementPointer()
fmt.Printf("多次增加后: %d\n", counter.GetCount()) // 变成3
counter.Reset()
fmt.Printf("重置后: %d\n", counter.GetCount()) // 变成0
}
方法集
package main
import "fmt"
type Person struct {
Name string
Age int
}
// 值接收者方法
func (p Person) GetName() string {
return p.Name
}
// 指针接收者方法
func (p *Person) SetName(name string) {
p.Name = name
}
func (p *Person) Birthday() {
p.Age++
}
func main() {
// 值类型
person1 := Person{Name: "Alice", Age: 25}
fmt.Printf("姓名: %s\n", person1.GetName())
// Go会自动转换为指针调用指针接收者方法
person1.SetName("Alice Smith")
person1.Birthday()
fmt.Printf("修改后: %+v\n", person1)
// 指针类型
person2 := &Person{Name: "Bob", Age: 30}
fmt.Printf("姓名: %s\n", person2.GetName()) // Go会自动解引用
person2.SetName("Bob Johnson")
person2.Birthday()
fmt.Printf("修改后: %+v\n", *person2)
}
接口
接口定义和实现
package main
import "fmt"
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
type Drawable interface {
Draw()
}
// 组合接口
type DrawableShape interface {
Shape
Drawable
}
// 实现接口的结构体
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
func (c Circle) Draw() {
fmt.Printf("绘制半径为%.2f的圆形\n", c.Radius)
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r Rectangle) Draw() {
fmt.Printf("绘制%gx%g的矩形\n", r.Width, r.Height)
}
// 使用接口的函数
func printShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
func drawShape(d Drawable) {
d.Draw()
}
func processDrawableShape(ds DrawableShape) {
printShapeInfo(ds)
drawShape(ds)
}
func main() {
circle := Circle{Radius: 5}
rectangle := Rectangle{Width: 4, Height: 6}
// 接口的多态性
shapes := []Shape{circle, rectangle}
for _, shape := range shapes {
printShapeInfo(shape)
}
// 组合接口
processDrawableShape(circle)
processDrawableShape(rectangle)
}
空接口
package main
import "fmt"
// 空接口可以存储任何类型的值
func printAnything(value interface{}) {
fmt.Printf("值: %v, 类型: %T\n", value, value)
}
func processValues(values ...interface{}) {
for i, value := range values {
fmt.Printf("参数%d: %v (类型: %T)\n", i, value, value)
}
}
func main() {
// 空接口可以接受任何类型
printAnything(42)
printAnything("Hello")
printAnything(3.14)
printAnything([]int{1, 2, 3})
printAnything(map[string]int{"a": 1})
// 可变参数的空接口
processValues(1, "hello", 3.14, true, []string{"a", "b"})
// 空接口切片
var items []interface{}
items = append(items, 1, "two", 3.0, true)
for i, item := range items {
fmt.Printf("items[%d] = %v\n", i, item)
}
}
错误处理
错误接口
package main
import (
"errors"
"fmt"
)
// error是一个内置接口
// type error interface {
// Error() string
// }
// 自定义错误类型
type ValidationError struct {
Field string
Message string
}
func (e ValidationError) Error() string {
return fmt.Sprintf("验证错误 - %s: %s", e.Field, e.Message)
}
// 返回错误的函数
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
func validateAge(age int) error {
if age < 0 {
return ValidationError{
Field: "age",
Message: "年龄不能为负数",
}
}
if age > 150 {
return ValidationError{
Field: "age",
Message: "年龄不能超过150岁",
}
}
return nil
}
func main() {
// 基本错误处理
result, err := divide(10, 0)
if err != nil {
fmt.Printf("错误: %v\n", err)
} else {
fmt.Printf("结果: %.2f\n", result)
}
// 自定义错误处理
if err := validateAge(-5); err != nil {
fmt.Printf("验证失败: %v\n", err)
// 类型断言检查具体错误类型
if ve, ok := err.(ValidationError); ok {
fmt.Printf("字段: %s, 消息: %s\n", ve.Field, ve.Message)
}
}
if err := validateAge(25); err != nil {
fmt.Printf("验证失败: %v\n", err)
} else {
fmt.Println("年龄验证通过")
}
}
defer语句
defer基础
package main
import "fmt"
func deferExample() {
fmt.Println("开始执行函数")
defer fmt.Println("这是第一个defer")
defer fmt.Println("这是第二个defer")
defer fmt.Println("这是第三个defer")
fmt.Println("函数主体执行")
// defer按LIFO顺序执行
// 输出顺序:
// 开始执行函数
// 函数主体执行
// 这是第三个defer
// 这是第二个defer
// 这是第一个defer
}
func main() {
deferExample()
}
defer的实际应用
package main
import (
"fmt"
"os"
)
// 文件操作示例
func readFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close() // 确保文件被关闭
// 读取文件内容
// ...
return nil
}
// 资源清理示例
func processData() {
fmt.Println("开始处理数据")
defer fmt.Println("数据处理完成,清理资源")
// 模拟数据处理
defer func() {
if r := recover(); r != nil {
fmt.Printf("捕获到panic: %v\n", r)
}
}()
// 可能发生panic的代码
// panic("模拟错误")
fmt.Println("数据处理中...")
}
func main() {
processData()
}
总结
本课我们深入学习了Go语言的函数和方法:
- 函数基础:定义、参数、返回值
- 多返回值:错误处理模式
- 可变参数:灵活的参数传递
- 函数作为值:高阶函数和函数类型
- 匿名函数和闭包:函数式编程特性
- 方法:为类型定义行为
- 接口:定义契约,实现多态
- 错误处理:Go的错误处理机制
- defer语句:延迟执行和资源清理
下一课预告
在下一课中,我们将学习Go语言的并发编程,包括:
- Goroutine的使用
- Channel通信机制
- Select语句
- 并发模式和最佳实践
💡 小贴士:理解接口是Go语言的核心概念,它实现了鸭子类型(duck typing),使得Go具有很强的表达能力和灵活性。
📚 文章对你有帮助?请关注我的公众号,万分感谢!
获取更多优质技术文章,第一时间掌握最新技术动态

关注公众号
第一时间获取最新技术文章

添加微信
技术交流 · 问题答疑 · 学习指导
评论讨论
欢迎留下你的想法和建议