【发布时间】:2021-05-20 04:54:50
【问题描述】:
我正在寻找一种将接口转换为具体类型以节省大量源代码的方法。
初始情况是网络服务器处理程序的两个功能。它们的区别仅在于一个函数解码结构数组,而另一个函数解码单个结构并将其存储在数据库中。根据类型不同,需要调用的函数是相同的。
要决定传递的是数组还是结构体,它会尝试将接口转换为类型,然后将其作为函数的参数适当地传递。与 documentation 和 stackoverflow post 中描述的类似。
但是,我没有得到预期的具体类型,程序总是运行到默认部分。我做错了什么或没有考虑到什么?
这些是默认部分的输出:
# 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)
}
case *types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x)
case map[string][]*types.Repository:
for i := range x {
for j := range x[i] {
err = rh.manager.AddOrUpdateRepository(context.Background(), x[i][j])
}
}
case []*types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x...)
case nil:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface is a type of nil")
return
default:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface does not match onto an array of repositories or a single repository struct: %T", x)
return
}
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to add repositories or repository")
rh.ulogger.Error("Failed to add repositories or repository: %v", err)
return
}
rw.WriteHeader(http.StatusCreated)
}
【问题讨论】:
-
注意:Go 根本没有类型转换。您所追求的是类型转换。
-
“一个函数解码一个结构数组”——另一个术语说明:这不是一个数组。这是一片。
-
您可能试图断言错误的类型。为了使调试更容易,请考虑在您的
default案例中添加类似这样的内容:fmt.Fprintf(rw, "Failed to assert type %T", v),这将显示您遇到的实际类型。