Go 語言函數類型的巧妙應用
函數類型在 Go 語言中非常強大,允許將函數作為值進行傳遞和操作。下面詳細介紹函數類型的各種妙用:
1. 回調函數
// 定義一個函數類型
type Callback func(int) int// 接受回調函數的函數
func processData(data []int, callback Callback) []int {result := make([]int, len(data))for i, v := range data {result[i] = callback(v)}return result
}// 使用示例
func main() {numbers := []int{1, 2, 3, 4, 5}// 使用匿名函數作為回調doubled := processData(numbers, func(x int) int {return x * 2})// 使用已定義函數作為回調squared := processData(numbers, square)fmt.Println(doubled) // [2 4 6 8 10]fmt.Println(squared) // [1 4 9 16 25]
}func square(x int) int {return x * x
}
2. 策略模式實現
type PaymentStrategy func(amount float64) boolfunc processPayment(amount float64, strategy PaymentStrategy) bool {return strategy(amount)
}// 各種支付策略
func creditCardPayment(amount float64) bool {// 信用卡支付邏輯return true
}func alipayPayment(amount float64) bool {// 支付寶支付邏輯return true
}// 使用示例
func pay(amount float64, paymentMethod string) bool {switch paymentMethod {case "credit":return processPayment(amount, creditCardPayment)case "alipay":return processPayment(amount, alipayPayment)default:return false}
}
3. 裝飾器模式
type HttpHandler func(w http.ResponseWriter, r *http.Request)// 日志裝飾器
func LoggingDecorator(handler HttpHandler) HttpHandler {return func(w http.ResponseWriter, r *http.Request) {fmt.Printf("Request: %s %s\n", r.Method, r.URL.Path)handler(w, r)fmt.Println("Request completed")}
}// 認證裝飾器
func AuthDecorator(handler HttpHandler) HttpHandler {return func(w http.ResponseWriter, r *http.Request) {// 檢查認證信息if authenticate(r) {handler(w, r)} else {http.Error(w, "Unauthorized", http.StatusUnauthorized)}}
}// 使用裝飾器
func main() {http.HandleFunc("/api/data", LoggingDecorator(AuthDecorator(handleData)))http.ListenAndServe(":8080", nil)
}func handleData(w http.ResponseWriter, r *http.Request) {// 業務邏輯
}
4. 函數選項模式
type Server struct {host stringport inttimeout time.DurationmaxConn int
}type ServerOption func(*Server)// 創建Server的選項函數
func WithHost(host string) ServerOption {return func(s *Server) {s.host = host}
}func WithPort(port int) ServerOption {return func(s *Server) {s.port = port}
}func WithTimeout(timeout time.Duration) ServerOption {return func(s *Server) {s.timeout = timeout}
}func WithMaxConn(maxConn int) ServerOption {return func(s *Server) {s.maxConn = maxConn}
}// 創建服務器
func NewServer(options ...ServerOption) *Server {// 設置默認值server := &Server{host: "localhost",port: 8080,timeout: 30 * time.Second,maxConn: 100,}// 應用所有選項for _, option := range options {option(server)}return server
}// 使用示例
func main() {server := NewServer(WithHost("example.com"),WithPort(9000),WithTimeout(60 * time.Second),)// 使用server...
}
5. 中間件鏈
type Middleware func(http.Handler) http.Handler// 中間件鏈
func Chain(middlewares ...Middleware) Middleware {return func(next http.Handler) http.Handler {for i := len(middlewares) - 1; i >= 0; i-- {next = middlewares[i](next)}return next}
}// 使用示例
func main() {handler := http.HandlerFunc(finalHandler)// 創建中間件鏈chain := Chain(loggingMiddleware,authMiddleware,rateLimitMiddleware,)// 應用中間件鏈http.Handle("/api", chain(handler))http.ListenAndServe(":8080", nil)
}
6. 延遲執行與鉤子函數
type ShutdownHook func()type App struct {shutdownHooks []ShutdownHook
}func (a *App) AddShutdownHook(hook ShutdownHook) {a.shutdownHooks = append(a.shutdownHooks, hook)
}func (a *App) Shutdown() {// 按照注冊順序的相反順序執行鉤子for i := len(a.shutdownHooks) - 1; i >= 0; i-- {a.shutdownHooks[i]()}
}// 使用示例
func main() {app := &App{}// 注冊數據庫關閉鉤子app.AddShutdownHook(func() {fmt.Println("關閉數據庫連接")})// 注冊文件清理鉤子app.AddShutdownHook(func() {fmt.Println("清理臨時文件")})// 應用運行...// 關閉應用app.Shutdown()
}
7. 操作集合的函數
type FilterFunc func(int) bool
type MapFunc func(int) int
type ReduceFunc func(int, int) int// 過濾集合
func Filter(nums []int, filter FilterFunc) []int {result := []int{}for _, n := range nums {if filter(n) {result = append(result, n)}}return result
}// 映射集合
func Map(nums []int, mapper MapFunc) []int {result := make([]int, len(nums))for i, n := range nums {result[i] = mapper(n)}return result
}// 歸約集合
func Reduce(nums []int, initialValue int, reducer ReduceFunc) int {result := initialValuefor _, n := range nums {result = reducer(result, n)}return result
}// 使用示例
func main() {numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}// 過濾偶數evens := Filter(numbers, func(n int) bool {return n%2 == 0})// 將數字翻倍doubled := Map(evens, func(n int) int {return n * 2})// 求和sum := Reduce(doubled, 0, func(acc, n int) int {return acc + n})fmt.Println("結果:", sum) // 60
}
8. 依賴注入
type UserRepository interface {FindByID(id int) (User, error)
}type UserService struct {repo UserRepository
}func NewUserService(repo UserRepository) *UserService {return &UserService{repo: repo}
}// 測試時可以輕松注入模擬實現
func TestUserService(t *testing.T) {mockRepo := &MockUserRepository{FindByIDFunc: func(id int) (User, error) {return User{ID: id, Name: "測試用戶"}, nil},}service := NewUserService(mockRepo)// 測試 service...
}
9. 自定義排序
type Person struct {Name stringAge int
}type SortBy func(p1, p2 *Person) booltype PersonSorter struct {people []Personless SortBy
}func (s PersonSorter) Len() int { return len(s.people) }
func (s PersonSorter) Swap(i, j int) { s.people[i], s.people[j] = s.people[j], s.people[i] }
func (s PersonSorter) Less(i, j int) bool { return s.less(&s.people[i], &s.people[j]) }// 使用示例
func main() {people := []Person{{"張三", 30},{"李四", 25},{"王五", 35},}// 按年齡排序sort.Sort(PersonSorter{people: people,less: func(p1, p2 *Person) bool {return p1.Age < p2.Age},})fmt.Println("按年齡排序:", people)// 按姓名排序sort.Sort(PersonSorter{people: people,less: func(p1, p2 *Person) bool {return p1.Name < p2.Name},})fmt.Println("按姓名排序:", people)
}
10. 惰性計算
type LazyEval func() interface{}func computeExpensiveValue() LazyEval {computed := falsevar result interface{}return func() interface{} {if !computed {fmt.Println("執行昂貴計算...")// 模擬耗時操作time.Sleep(1 * time.Second)result = 42computed = true}return result}
}// 使用示例
func main() {// 創建惰性計算lazy := computeExpensiveValue()fmt.Println("惰性計算創建后,尚未執行計算")// 調用時才執行實際計算value := lazy()fmt.Println("第一次獲取值:", value)// 再次調用不會重復計算value = lazy()fmt.Println("第二次獲取值:", value)
}
函數類型使 Go 擁有了函數式編程的部分能力,同時保持了語言的簡潔性和性能,這使得它在構建靈活、可測試和可維護的代碼時非常有價值。