一、函数基础
1.1 函数声明
go
// 基本语法
func 函数名(参数列表) (返回值列表) {
// 函数体
}
// 示例
func add(x int, y int) int {
return x + y
}
// 简化参数类型(相同类型)
func multiply(x, y int) int {
return x * y
}
1.2 多返回值
go
// 返回多个值
func swap(x, y string) (string, string) {
return y, x
}
// 命名返回值
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 裸返回,自动返回x和y
}
二、函数类型与高级特性
2.1 函数作为值
go
func main() {
// 函数赋值给变量
add := func(x, y int) int {
return x + y
}
fmt.Println(add(3, 4)) // 7
// 函数作为参数
calculate := func(fn func(int, int) int, a, b int) int {
return fn(a, b)
}
result := calculate(add, 5, 3)
fmt.Println(result) // 8
}
2.2 闭包
go
// 返回函数的函数
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i), // 0, 1, 3, 6, 10...
neg(-2*i), // 0, -2, -6, -12...
)
}
}
2.3 可变参数
go
// ... 表示可变参数
func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
// 切片作为可变参数
nums := []int{1, 2, 3, 4}
fmt.Println(sum(nums...)) // 10
}
三、方法与接收者
3.1 方法定义
go
type Rectangle struct {
width, height float64
}
// 值接收者
func (r Rectangle) area() float64 {
return r.width * r.height
}
// 指针接收者(可以修改结构体)
func (r *Rectangle) scale(factor float64) {
r.width *= factor
r.height *= factor
}
func main() {
rect := Rectangle{width: 3, height: 4}
fmt.Println(rect.area()) // 12
rect.scale(2)
fmt.Println(rect.width, rect.height) // 6 8
}
3.2 接收者选择
go
type Counter struct {
value int
}
// 值接收者:不修改原对象,适用于小型结构体
func (c Counter) GetValue() int {
return c.value
}
// 指针接收者:需要修改对象或避免复制大对象
func (c *Counter) Increment() {
c.value++
}
// 指针接收者:确保一致性(推荐)
func (c *Counter) Decrement() {
c.value--
}
四、函数高级特性
4.1 延迟执行(defer)
go
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close() // 确保文件被关闭
// 多个defer按LIFO顺序执行
defer fmt.Println("文件处理完成")
defer fmt.Println("清理临时资源")
// 处理文件...
return nil
}
4.2 匿名函数
go
func main() {
// 立即执行函数
func() {
fmt.Println("立即执行")
}()
// 延迟执行的匿名函数
defer func() {
fmt.Println("延迟执行")
}()
// 作为回调
nums := []int{1, 2, 3, 4}
squares := make([]int, len(nums))
for i, v := range nums {
func(x int) {
squares[i] = x * x
}(v)
}
fmt.Println(squares) // [1 4 9 16]
}
4.3 错误处理函数
go
// 返回错误的函数
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// 带错误处理的辅助函数
func mustDivide(a, b float64) float64 {
result, err := divide(a, b)
if err != nil {
panic(err)
}
return result
}
五、接口与函数
5.1 函数类型实现接口
go
type Handler func(string) string
// 为函数类型添加方法
func (h Handler) Process(s string) string {
return h(s)
}
// 函数作为接口实现
type StringProcessor interface {
Process(string) string
}
func main() {
var processor StringProcessor
// 函数转换为Handler类型
upper := Handler(strings.ToUpper)
processor = upper
fmt.Println(processor.Process("hello")) // HELLO
}
5.2 回调函数模式
go
type FilterFunc func(int) bool
func filter(numbers []int, fn FilterFunc) []int {
var result []int
for _, n := range numbers {
if fn(n) {
result = append(result, n)
}
}
return result
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
// 偶数筛选
even := filter(numbers, func(n int) bool {
return n%2 == 0
})
// 大于5筛选
large := filter(numbers, func(n int) bool {
return n > 5
})
fmt.Println(even) // [2 4 6 8]
fmt.Println(large) // [6 7 8 9]
}
六、最佳实践与模式
6.1 函数选项模式
go
type Server struct {
host string
port int
timeout time.Duration
}
type Option func(*Server)
func WithHost(host string) Option {
return func(s *Server) {
s.host = host
}
}
func WithPort(port int) Option {
return func(s *Server) {
s.port = port
}
}
func WithTimeout(timeout time.Duration) Option {
return func(s *Server) {
s.timeout = timeout
}
}
func NewServer(opts ...Option) *Server {
s := &Server{
host: "localhost",
port: 8080,
timeout: 30 * time.Second,
}
for _, opt := range opts {
opt(s)
}
return s
}
func main() {
// 使用选项模式
server := NewServer(
WithHost("127.0.0.1"),
WithPort(9000),
WithTimeout(60*time.Second),
)
}
6.2 中间件模式
go
type Middleware func(http.HandlerFunc) http.HandlerFunc
func logging(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next(w, r)
fmt.Printf("请求处理耗时: %v\n", time.Since(start))
}
}
func auth(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "未授权", http.StatusUnauthorized)
return
}
next(w, r)
}
}
// 组合中间件
func chain(middlewares ...Middleware) Middleware {
return func(next http.HandlerFunc) http.HandlerFunc {
for i := len(middlewares) - 1; i >= 0; i-- {
next = middlewares[i](next)
}
return next
}
}
七、性能考虑
7.1 内联优化
go
// 小函数会被编译器内联
func add(a, b int) int {
return a + b
}
// 避免复杂函数影响内联
func complexCalculation(x, y int) int {
// 复杂逻辑...
return result
}
7.2 内存分配
go
// 避免在热路径中分配内存
func process(data []byte) {
// 复用缓冲区
var buf [1024]byte
// ... 处理逻辑
}
// 使用sync.Pool重用对象
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 0, 1024)
},
}
总结要点
-
函数设计原则
- 保持函数简短(建议不超过50行)
- 单一职责原则
- 良好的命名和文档
-
错误处理
- 使用多返回值处理错误
- 尽早返回错误
- 提供上下文信息
-
性能考虑
- 小函数有利于内联
- 避免不必要的内存分配
- 合理使用指针接收者
-
代码组织
- 相关函数分组
- 使用接口抽象行为
- 遵循Go惯用模式