如何减少 Golang 中重复函数的冗余代码?
How can I reduce redundant code of duplicate function in Golang?
我有一个 Rest API 应用程序可以将所有 json 数据列出到浏览器。只要我有更多模块,我的代码就更加冗余。和复杂。
func UserList(w http.ResponseWriter, r *http.Request) {
list := []models.User{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
func ProductList(w http.ResponseWriter, r *http.Request) {
list := []models.Product{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
func OrderList(w http.ResponseWriter, r *http.Request) {
list := []models.Order{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
有没有更好的办法把这段代码做成一个函数
示例
func List(w http.ResponseWriter, r *http.Request) {
list := ??? List of struct here ???
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
如果您将模型类型作为请求参数传递,应该这样做(包括错误处理):
func List(w http.ResponseWriter, r *http.Request) {
var list interface{}
switch r.FormValue("model") {
case "user":
list = new([]models.User)
case "product":
list = new([]models.Product)
case "order":
list = new([]models.Order)
default:
http.Error(w, "invalid type", http.StatusBadRequest)
return
}
if err := db.Find(list); err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(list); err != nil {
log.Printf("json encoding error: %v", err)
}
}
另一种选择是构建类型注册表,甚至可以分解出切片创建,使用 reflect
:
的帮助
var reg = map[string]reflect.Type{
"user": reflect.TypeOf((*models.User)(nil)).Elem(),
"product": reflect.TypeOf((*models.Product)(nil)).Elem(),
"order": reflect.TypeOf((*models.Order)(nil)).Elem(),
}
func List(w http.ResponseWriter, r *http.Request) {
etype := reg[r.FormValue("model")]
if etype == nil {
http.Error(w, "invalid type", http.StatusBadRequest)
return
}
list := reflect.New(reflect.SliceOf(etype)).Interface()
if err := db.Find(list); err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(list); err != nil {
log.Printf("json encoding error: %v", err)
}
}
你可以这样做:
func List(list interface{}, w http.ResponseWriter, r *http.Request,) {
db.Find(list)
json.NewEncoder(w).Encode(list)
}
鉴于您正在调用 db.Find(&list)
我假设它们共享一个公共接口。在这种情况下,您可以像这样包装您的处理程序调用;
func ListHandler(list <YOUR_INTERFACE>) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
}
在你的呼唤中;
http.HandleFunc("/user/list", ListHandler([]models.User{}))
http.HandleFunc("/product/list", ListHandler([]models.Product{}))
http.HandleFunc("/order/list", ListHandler([]models.Order{}))
我有一个 Rest API 应用程序可以将所有 json 数据列出到浏览器。只要我有更多模块,我的代码就更加冗余。和复杂。
func UserList(w http.ResponseWriter, r *http.Request) {
list := []models.User{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
func ProductList(w http.ResponseWriter, r *http.Request) {
list := []models.Product{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
func OrderList(w http.ResponseWriter, r *http.Request) {
list := []models.Order{}
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
有没有更好的办法把这段代码做成一个函数 示例
func List(w http.ResponseWriter, r *http.Request) {
list := ??? List of struct here ???
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
如果您将模型类型作为请求参数传递,应该这样做(包括错误处理):
func List(w http.ResponseWriter, r *http.Request) {
var list interface{}
switch r.FormValue("model") {
case "user":
list = new([]models.User)
case "product":
list = new([]models.Product)
case "order":
list = new([]models.Order)
default:
http.Error(w, "invalid type", http.StatusBadRequest)
return
}
if err := db.Find(list); err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(list); err != nil {
log.Printf("json encoding error: %v", err)
}
}
另一种选择是构建类型注册表,甚至可以分解出切片创建,使用 reflect
:
var reg = map[string]reflect.Type{
"user": reflect.TypeOf((*models.User)(nil)).Elem(),
"product": reflect.TypeOf((*models.Product)(nil)).Elem(),
"order": reflect.TypeOf((*models.Order)(nil)).Elem(),
}
func List(w http.ResponseWriter, r *http.Request) {
etype := reg[r.FormValue("model")]
if etype == nil {
http.Error(w, "invalid type", http.StatusBadRequest)
return
}
list := reflect.New(reflect.SliceOf(etype)).Interface()
if err := db.Find(list); err != nil {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(list); err != nil {
log.Printf("json encoding error: %v", err)
}
}
你可以这样做:
func List(list interface{}, w http.ResponseWriter, r *http.Request,) {
db.Find(list)
json.NewEncoder(w).Encode(list)
}
鉴于您正在调用 db.Find(&list)
我假设它们共享一个公共接口。在这种情况下,您可以像这样包装您的处理程序调用;
func ListHandler(list <YOUR_INTERFACE>) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
db.Find(&list)
json.NewEncoder(w).Encode(list)
}
}
在你的呼唤中;
http.HandleFunc("/user/list", ListHandler([]models.User{}))
http.HandleFunc("/product/list", ListHandler([]models.Product{}))
http.HandleFunc("/order/list", ListHandler([]models.Order{}))