为了账号安全,请及时绑定邮箱和手机立即绑定

浇注接口到混凝土型 - 型开关

浇注接口到混凝土型 - 型开关

Go
森林海 2022-08-09 20:16:46
我正在寻找一种方法将接口转换为具体类型以节省大量源代码。初始情况是 Web 服务器处理程序的两个函数。它们的不同之处仅在于一个函数解码结构数组,另一个函数解码单个结构并将其存储在数据库中。必须调用以进行保存的函数是相同的,具体取决于类型。若要确定是传递数组还是结构,请尝试将接口转换为类型,然后将其作为函数的参数相应地传递。与文档和堆栈溢出帖子中描述的类似。但是,我没有按预期获得具体类型,并且程序始终运行到默认部分。我做错了什么,或者我没有考虑到什么?这些是默认部分的输出:# interface is a struct... or a single repository struct: map[string]interface{}# interface is an array of structs... or a single repository struct: []interface{}以下是带有函数的源代码func (rh *RouteHandler) AddOrUpdateRepository(rw http.ResponseWriter, req *http.Request) {    repository := new(types.Repository)    rh.addOrUpdateRepositories(rw, req, repository)}func (rh *RouteHandler) AddOrUpdateRepositories(rw http.ResponseWriter, req *http.Request) {    repositories := make([]*types.Repository, 0)    rh.addOrUpdateRepositories(rw, req, repositories)}func (rh *RouteHandler) addOrUpdateRepositories(rw http.ResponseWriter, req *http.Request, v interface{}) {    defer req.Body.Close()    switch req.Header.Get("Content-Type") {    case "application/xml":        xmlDecoder := xml.NewDecoder(req.Body)        err := xmlDecoder.Decode(&v)        if err != nil {            rw.WriteHeader(http.StatusInternalServerError)            fmt.Fprintf(rw, "Failed to decode repositories or repository")            rh.ulogger.Error("Failed to decode repositories or repository: %v", err)            return        }    case "application/json":        fallthrough    default:        jsonDecoder := json.NewDecoder(req.Body)        err := jsonDecoder.Decode(&v)        if err != nil {            rw.WriteHeader(http.StatusInternalServerError)            fmt.Fprintf(rw, "Failed to decode repositories or repository")            rh.ulogger.Error("Failed to decode repositories or repository: %v", err)            return        }    }    var err error    switch x := v.(type) {    case map[string]*types.Repository:        for _, repository := range x {            err = rh.manager.AddOrUpdateRepository(context.Background(), repository)        }   
查看完整描述

1 回答

?
RISEBY

TA贡献1856条经验 获得超5个赞

(稍微简化一下。


您有一个具有以下签名的函数:


func addOrUpdateRepositories(v interface{})

然后你这样称呼它:


repository := new(types.Repository)

addOrUpdateRepositories(repository)

就像这样:


repositories := make([]*types.Repository, 0)

addOrUpdateRepositories(repositories)

在第一次调用中,存储的值的具体类型将是(作为返回指向分配值的指针),在第二次调用中,存储的值的具体类型将是 - 因为这是被告知要创建的内容。v*types.Repositorynewv[]*types.Repositorymake


现在,您在 上执行类型开关,其内容为:v


switch x := v.(type) {

case map[string]*types.Repository:

case map[string][]*types.Repository:

case nil:

default:

}

撇开以下情况不谈:如果您不将其称为传递 a,则不会在问题的代码段中发生,则 将始终选择默认分支,因为存储在 中的具体值的类型是 never 或 。addOrUpdateRepositoriesnilvswitchvmap[string]*types.Repositorymap[string][]*types.Repository


我不确定为什么你没有看到这一点,所以也许你应该完善你的问题,或者可能试图在评论我的答案时澄清你的困惑?


另一个黑暗中的镜头:类型转换(请注意,Go没有类型转换,正如@Flimzy指出的那样)和Go中的类型切换实际上并没有改变它们所操作的值的基础表示形式 - 除了有限的一组(“每个人都期望如此”)情况,例如类型转换为a到,这些情况被精确地记录下来。float64int64


因此,您不能获取一个(指向类型值的一部分指针)并以某种方式强制它“成为”:由于多种原因,这将是一件荒谬的事情,最明显的是:如果您正在编写Go编译器,您将如何执行这样的“类型转换”?假设您真的要分配一个地图,但是应该为该地图中的哪个键分配原始(源)切片?将 a 类型转换为 ?[]*types.Repositorytypes.Repositorymap[string][]*types.Repository[]*types.Repositorystruct {foo []*types.Repository; bar []*types.Repository}


查看完整回答
反对 回复 2022-08-09
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号