猿问

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

我正在寻找一种方法将接口转换为具体类型以节省大量源代码。


初始情况是 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)

        }

   

森林海
浏览 104回答 1
1回答

RISEBY

(稍微简化一下。您有一个具有以下签名的函数:func addOrUpdateRepositories(v interface{})然后你这样称呼它:repository := new(types.Repository)addOrUpdateRepositories(repository)就像这样:repositories := make([]*types.Repository, 0)addOrUpdateRepositories(repositories)在第一次调用中,存储的值的具体类型将是(作为返回指向分配值的指针),在第二次调用中,存储的值的具体类型将是 - 因为这是被告知要创建的内容。v*types.Repositorynewv[]*types.Repositorymake现在,您在 上执行类型开关,其内容为:vswitch 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}
随时随地看视频慕课网APP

相关分类

Go
我要回答