Go – 将通用结构传递给函数

huangapple go评论85阅读模式
英文:

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,你可以检查错误类型。当尝试对无效类型(如chanfunc)进行编组时,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")
    }
}

huangapple
  • 本文由 发表于 2015年11月25日 20:03:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/33916050.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定