showliuzp 2025-09-27 18:41 采纳率: 84.3%
浏览 4
已结题

golang封装controller回调函数报错


server.go

package services
 
type TokenDetail struct {
    Token       *string
    TokenDetail *iapi.LoginToken
}
 
// WithTokenAccountValidation 是一个中间件函数,用于包装带有 Token 验证的 handler
func WithTokenAccountValidation(handler func(req interface{}, token *TokenDetail) (interface{}, error)) func(interface{}, *TokenDetail) (interface{}, error) {
    return func(req interface{}, token *TokenDetail) (interface{}, error) {
        // 这里可以添加 Token 验证逻辑
        if token == nil || token.Token == nil || *token.Token == "" {
            return nil, fmt.Errorf("无效的 Token")
        }
 
        return handler(req, token)
    }
}


controller.go

 
// GenericHandler 是一个通用的 handler 类型,接收 req 和 token,并返回结果和错误
type GenericHandler func(req interface{}, token *services.TokenDetail) (interface{}, error)
 
// AfterTokenAccountValidation 是一个通用的验证函数,支持动态传入业务逻辑
func AfterTokenAccountValidation(req interface{}, token string, handlerFunc GenericHandler) (interface{}, error) {
    tokenDetail := &services.TokenDetail{
        Token: &token,
    }
 
    // 使用中间件包装 handler
    wrappedHandler := services.WithTokenAccountValidation(handlerFunc)
 
    return wrappedHandler(req, tokenDetail)
}


services.go

type UserStreamer struct{
    LogTag string
}

func NewUserStreamer() *UserStreamer{
    obj := new(UserStreamer)
    obj.LogTag = "services.user_streamer"

    return obj
}


//用户管理
func (u *UserStreamer) UserStreamerPaymentAccount(req *iapi.UserStreamerPaymentAccountReq, token TokenDetail)(resp interface{},err error){
    funs_log_tag := "用户管理-主播列表"

    return
}

controller.go
func UserStreamerPaymentAccount(r *http.Request) (resp interface{},err error){
    var req = new(iapi.UserStreamerPaymentAccountReq)
    if resp,err = ParseReq(r,&req,"用户管理-主播列表-添加/编辑收款账号,前端参数错误",log_tag_user_streamer);err != nil{
        return
    }

    authorization := (*r).Header.Get(types.HEADER_AUTH)
    resp, err = AfterTokenAccountValidation(req, authorization, NewUserStreamer().UserStreamerPaymentAccount)
   

    return

}


我想通过AfterTokenAccountValidation函数调用service.go的某个方法,就如controller.go里的UserStreamerPaymentAccount一样,但报错: cannot use user_streamer_obj.UserStreamerPaymentAccount (value of type func(req *iapi.UserStreamerPaymentAccountReq, token services.TokenDetail) (resp interface{}, err error)) as GenericHandler value in argument to AfterTokenAccountValidation
  • 写回答

5条回答 默认 最新

  • 檀越@新空间 2025-09-27 18:42
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    你遇到的错误是因为 函数签名不匹配,导致无法将 UserStreamerPaymentAccount 方法作为 GenericHandler 类型传递给 AfterTokenAccountValidation 函数。


    问题分析

    1. GenericHandler 的定义如下:

    type GenericHandler func(req interface{}, token *services.TokenDetail) (interface{}, error)
    

    它期望一个函数接收两个参数:

    • req interface{}
    • token *services.TokenDetail

    返回值为 (interface{}, error)


    2. 你定义的 UserStreamerPaymentAccount 方法如下:

    func (u *UserStreamer) UserStreamerPaymentAccount(req *iapi.UserStreamerPaymentAccountReq, token TokenDetail)(resp interface{},err error){
        ...
    }
    

    这个方法的参数是:

    • req *iapi.UserStreamerPaymentAccountReq
    • token TokenDetail

    注意:类型不一致req 是具体的结构体类型(不是 interface{}),而 tokenTokenDetail(而不是 *TokenDetail)。


    3. 你调用 AfterTokenAccountValidation 时传入的是:

    NewUserStreamer().UserStreamerPaymentAccount
    

    这是一个方法指针,其类型为:

    func(*iapi.UserStreamerPaymentAccountReq, services.TokenDetail) (interface{}, error)
    

    GenericHandler 要求的是:

    func(interface{}, *services.TokenDetail) (interface{}, error)
    

    所以,函数签名不匹配,导致编译器报错。


    解决方案

    解决方案 1:调整 UserStreamerPaymentAccount 方法的签名

    将方法改为符合 GenericHandler 的签名:

    func (u *UserStreamer) UserStreamerPaymentAccount(req interface{}, token *services.TokenDetail) (interface{}, error) {
        // 将 req 强制转换为 *iapi.UserStreamerPaymentAccountReq
        reqTyped, ok := req.(*iapi.UserStreamerPaymentAccountReq)
        if !ok {
            return nil, fmt.Errorf("invalid request type")
        }
    
        // 使用 token 的值
        // ... your logic here ...
    
        return resp, err
    }
    

    重点:
    函数签名必须与 GenericHandler 完全一致。


    解决方案 2:使用适配器函数(Adapter Function)进行包装

    如果你不想修改原始方法的签名,可以使用一个适配器函数来桥接:

    func adaptUserStreamerPaymentAccount(handler func(*iapi.UserStreamerPaymentAccountReq, services.TokenDetail) (interface{}, error)) GenericHandler {
        return func(req interface{}, token *services.TokenDetail) (interface{}, error) {
            // 强制转换 req
            reqTyped, ok := req.(*iapi.UserStreamerPaymentAccountReq)
            if !ok {
                return nil, fmt.Errorf("invalid request type")
            }
    
            // 调用原方法
            return handler(reqTyped, *token)
        }
    }
    

    然后在调用时使用这个适配器:

    handler := adaptUserStreamerPaymentAccount(NewUserStreamer().UserStreamerPaymentAccount)
    resp, err = AfterTokenAccountValidation(req, authorization, handler)
    

    解决方案 3:修改 AfterTokenAccountValidation 的参数类型

    如果可以接受,也可以将 AfterTokenAccountValidation 改为支持更灵活的参数类型:

    func AfterTokenAccountValidation(req interface{}, token string, handlerFunc func(interface{}, *services.TokenDetail) (interface{}, error)) (interface{}, error) {
        tokenDetail := &services.TokenDetail{
            Token: &token,
        }
    
        wrappedHandler := services.WithTokenAccountValidation(handlerFunc)
    
        return wrappedHandler(req, tokenDetail)
    }
    

    这样你就可以直接传入一个兼容的函数。


    总结

    | 问题 | 原因 | 解决方案 | |------|------|----------| | 报错 cannot use user_streamer_obj.UserStreamerPaymentAccount as GenericHandler | 函数签名不匹配 | 调整方法签名使用适配器函数 | | req 类型不一致 | UserStreamerPaymentAccount 接收的是 *iapi.UserStreamerPaymentAccountReq,而 GenericHandler 接收的是 interface{} | 使用类型断言或适配器 | | token 类型不一致 | UserStreamerPaymentAccount 接收的是 TokenDetail,而 GenericHandler 接收的是 *TokenDetail | 修改方法签名或使用适配器 |


    ✅ 最终建议代码(推荐)

    修改后的 UserStreamerPaymentAccount 方法:

    func (u *UserStreamer) UserStreamerPaymentAccount(req interface{}, token *services.TokenDetail) (interface{}, error) {
        reqTyped, ok := req.(*iapi.UserStreamerPaymentAccountReq)
        if !ok {
            return nil, fmt.Errorf("invalid request type")
        }
    
        // 你的业务逻辑
        // ...
    
        return resp, err
    }
    

    调用方式:

    resp, err = AfterTokenAccountValidation(req, authorization, NewUserStreamer().UserStreamerPaymentAccount)
    

    如需我帮你生成完整的可运行示例代码,请告诉我你希望如何组织项目结构。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 10月9日
  • 已采纳回答 10月1日
  • 创建了问题 9月27日