英文:
Go - passing generic struct to function
问题
考虑以下代码,该代码响应GET '/venues/:id'请求:
func venueShow(w http.ResponseWriter, req *http.Request) {
// 从参数中获取ID
vars := mux.Vars(req)
id := vars["id"]
// 初始化新的结构体
var venue Venue
// 根据ID选择并将结果扫描到结构体中
db.First(&venue, id).Scan(&venue)
// 转换为JSON
response := structToJSON(&venue)
// 设置响应头并提供响应
w.Header().Set("Content-Type", "application/json")
w.Write(response)
}
以及:
func structToJSON(s interface{}) (response []byte) {
// 将其转换为格式化的JSON
response, err := json.MarshalIndent(&s, "", " ")
if err != nil {
return []byte("Venue does not exist")
}
// 返回JSON作为响应
return response
}
我的structToJSON函数接受一个空接口作为参数,因为我想将各种不同的结构体传递给该函数,并将它们转换为JSON。
然而,我觉得这样不太安全。如果任何东西都满足空接口,我可以将任何我想要的东西传递给该函数,当json.Marshal尝试进行处理时,可能会发生各种错误。这(我猜)会在编译时而不是运行时被捕获,但是否有更安全的方法?
我可以为每种不同类型的结构体/模型复制structToJSON方法,但这样做不太符合DRY原则。
谢谢。
英文:
Considering the following code, which is responding to GET '/venues/:id':
func venueShow(w http.ResponseWriter, req *http.Request) {
// get ID from params
vars := mux.Vars(req)
id := vars["id"]
// initialise new struct
var venue Venue
// select by id and scan into struct
db.First(&venue, id).Scan(&venue)
// turn it to json
response := structToJSON(&venue)
// write headers and provide response
w.Header().Set("Content-Type", "application/json")
w.Write(response)
}
and:
func structToJSON (s interface{}) (response []byte) {
// turn it into pretty-ish json
response, err := json.MarshalIndent(&s, "", " ")
if err != nil {
return []byte("Venue does not exist")
}
// return the json as the reponse
return response
}
My structToJSON function is taking an empty interface as the argument, because I want to pass various different structs to the function and have them spewed out as JSON.
However, it doesn't strike me as very safe. If anything satisfies an empty interface, I could pass whatever I wanted into that function, and all sorts of errors might happen when json.Marshal tries to do it's business. This (I suppose) would be caught by the compiler rather than at runtime, but is there a safer way?
I could duplicate the structToJSON method for each different type of Struct/Model that I pass to it, but that's not very DRY.
Thanks
答案1
得分: 6
Marshal函数也将其参数作为interface{}
接收,因此无法在编译时检测到是否传递了无效的内容,所有这些都在运行时捕获。
要检查是否将无效类型传递给Marshal,你可以检查错误类型。当尝试对无效类型(如chan
或func
)进行编组时,Marshal会返回UnsupportedTypeError
,因此你可以在编组时检查该错误。
所以你可以尝试这样做:
if err != nil {
_, ok := err.(*json.UnsupportedTypeError)
if ok {
return []byte("尝试编组无效类型")
} else {
return []byte("场馆不存在")
}
}
英文:
The Marshal function also receives its parameters as interface{}
therefore there's no way to detect if you are passing something invalid at compile time, it's all caught at runtime.
One thing you can do to check if an invalid type was passed to Marshal is to check the error type, Marshal returns an UnsupportedTypeError
when you try to Marshal an invalid type (like chan
or func
) so you can check for that error when Marshaling.
So you could try something like that:
if err != nil {
_, ok := err.(*json.UnsupportedTypeError)
if ok {
return []byte("Tried to Marshal Invalid Type")
} else {
return []byte("Venue does not exist")
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论