Go - 将通用结构体传递给函数

8
考虑以下代码,该代码响应 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)
}

并且:

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
}

我的structToJSON函数以空接口作为参数,因为我想将各种不同的结构体传递给该函数,并将它们输出为JSON。但是,这似乎并不是很安全。如果任何东西都能满足空接口,我可以将任何我想要的东西传递到该函数中,当json.Marshal尝试执行其操作时就会发生各种错误。这(我想)会被编译器捕获而非在运行时捕获,但是否有更安全的方法呢?我可以为每种不同类型的Struct/Model复制structToJSON方法,但这不太符合DRY原则。谢谢。

1
如何考虑一个“可JSON化”的接口,让结构体自己知道如何编组?不幸的是,我没有完整的答案,但这样你就可以将structToJSON的要求移动到自己的对象中。 - Peter Mellett
1个回答

6

Marshal函数也将其参数作为interface{}接收,因此无法在编译时检测传递的参数是否无效,所有错误都在运行时捕获。

您可以做的一件事是检查是否将无效类型传递给了Marshal,可以检查错误类型,当您尝试对无效类型(如chanfunc)进行Marshal时,Marshal会返回UnsupportedTypeError,因此在Marshaling时可以检查该错误。

因此,您可以尝试以下操作:

if err != nil {
    _, ok := err.(*json.UnsupportedTypeError)
    if ok {
        return []byte("Tried to Marshal Invalid Type")
    } else {
        return []byte("Venue does not exist")
    }
}

啊,好的,我没想到。所以使用空接口作为参数并没有什么实际问题,因为标准库中的东西也会这样做吧。谢谢。我会将其标记为正确的! - Ralph King
1
是的,因为 Go 没有泛型并且不允许方法重载,我们只能通过传递 interface{} 作为参数来解决问题。 - hbejgel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接