Golang中函数参数的使用与技巧

Golang中函数参数的使用与技巧 Screenshot 2020-04-23 at 16.04.45

为了方便,我想通过创建一个如下结构体来缩短 AddHandler 的函数参数: Screenshot 2020-04-23 at 16.12.37

并用这个结构体代替 w http.ResponseWriter, r *http.Request 参数。 一切看起来都没问题,但我该如何处理这个错误? Screenshot 2020-04-23 at 16.10.25

这个错误之所以出现,是因为 http.HandleFunc 只能接受参数为 w http.ResponseWriter, r *http.Request 的处理函数: Screenshot 2020-04-23 at 16.18.41


更多关于Golang中函数参数的使用与技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

有几种方法可以实现这个功能:

传递给 AddHandler 的函数可以将这些值包装到一个 CoronavirusRelay 结构体中,然后调用另一个处理函数:

type CoronavirusRelay {
    request *http.Request
    writer http.ResponseWriter
}

func myCoronavirusRelayFunc(CoronavirusRelay cr) {
    // ...
}

func main() {
    // ...
    s.AddHandler("/test", func(w http.ResponseWriter, r *http.Request) {
        myCoronavirusRelayFunc(CoronavirusRelay{request: r, writer: w})
    })
    // ...
}

如果你需要频繁这样做,可能需要一个工厂函数:

func CoronavirusRelayFunc(f func(cr CoronavirusRelay)) func(w http.ResponseWriter, r *http.Request) {
    return func(w http.ResponseWriter, r *http.Request) {
        f(CoronavirusRelay{reader: r, writer: w})
    }
}

func main() {
    // ...
    s.AddHandler("/test", CoronavirusRelayFunc(myCoronavirusRelayFunc))
    s.AddHandler("/test2", CoronavirusRelayFunc(myCoronavirusRelayFunc2))
    // etc ...
}

更多关于Golang中函数参数的使用与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中,http.HandleFunc 要求处理函数的签名必须是 func(http.ResponseWriter, *http.Request)。要使用自定义结构体作为参数,可以通过适配器模式或闭包来包装处理函数。以下是两种解决方案:

方案1:使用适配器函数

创建一个适配器函数,将自定义结构体处理函数转换为标准 http.HandlerFunc

package main

import (
    "net/http"
)

// 自定义结构体
type HandlerArgs struct {
    W http.ResponseWriter
    R *http.Request
}

// 自定义处理函数类型
type CustomHandler func(HandlerArgs)

// 适配器:将 CustomHandler 转换为 http.HandlerFunc
func AdaptHandler(h CustomHandler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        args := HandlerArgs{W: w, R: r}
        h(args)
    }
}

// 示例处理函数
func MyHandler(args HandlerArgs) {
    args.W.WriteHeader(http.StatusOK)
    args.W.Write([]byte("Hello with custom struct"))
}

func main() {
    http.HandleFunc("/", AdaptHandler(MyHandler))
    http.ListenAndServe(":8080", nil)
}

方案2:使用闭包直接包装

在注册路由时,通过闭包将自定义结构体处理函数嵌入标准签名中。

package main

import (
    "net/http"
)

type HandlerArgs struct {
    W http.ResponseWriter
    R *http.Request
}

func MyHandler(args HandlerArgs) {
    args.W.WriteHeader(http.StatusOK)
    args.W.Write([]byte("Hello with closure"))
}

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        args := HandlerArgs{W: w, R: r}
        MyHandler(args)
    })
    http.ListenAndServe(":8080", nil)
}

这两种方案都允许在保持 http.HandleFunc 兼容性的同时使用自定义结构体参数。适配器方案更适用于多个路由重用,闭包方案则更直接灵活。

回到顶部