dpjhq00684 2017-07-28 08:11
浏览 46
已采纳

在Golang中将错误片转换为结构片

I'm using the Golang validate library to do some input error checking as part of an API (a silly demo API for learning purposes).

When one performs the validation a slice of errors is returned. In reality, the slice is made up of the validate library's struct BadField, which looks like this:

type BadField struct {
    Field string
    Err   error
}

func (b BadField) Error() string {
    return fmt.Sprintf("field %s is invalid: %v", b.Field, b.Err)
}

I'd like to pass around a more-specific slice, so rather than []error I would like have []BadField so that I can access the Field value.

So far I can't find a way of casting/converting from one to the other. Maybe there isn't one (due to the nature of go and slices). Maybe there's a package that will do this for me.

My initial implementation

The way I've come up with is to loop through the slice and cast each element individually.

errors := valueWithBadStuff.Validate()

validationErrors := make([]validate.BadField, len(errors))
for _, err := range errors {
    validationError, ok := err.(validate.BadField)
    if !ok {
        panic("badarghfiremyeyes") // S/O purposes only
    }
    validationErrors = append(validationErrors, validationError)
}

Which feels kinda long for something "simple" but perhaps there's a more go idiomatic way? Or a nicer way?

For background, my intention (at the moment) is to take the slice of validation errors and pipe it back to the client as an array of JSON objects with the Field name and the error message (i.e. for a fictional age field: ["field_name": "age", "Cannot be less than 0"])

Just after the loop above I do more conversion to generate a slice of structs that are tagged with json that will actually go the client. The extra conversion may be duplication and pointless but, right now, it's purely a learning piece and I'll probably refactor it in an hour or two.

  • 写回答

1条回答 默认 最新

  • dq62957 2017-07-28 08:23
    关注

    There's not really a "nicer" way of doing this. To convert a slice you have to basically do what you've already discovered.

    If you are simply returning these errors to a client, you could probably avoid the need to typecast this at all.

    Implement the JSON Marshaler interface and you can make your type will automatically output the JSON in the format you desire. For example, for the format you gave above this would be:

    func (e BadField)  MarshalJSON() ([]byte, error) {
       return json.Marshal([]string{"field_name",e.Field,e.Err.Error()})
    }
    

    I suspect however that you would probably rather have a response something like:

    [  
       {  
          "field":"age",
          "error":"msg1"
       },
       {  
          "field":"name",
          "error":"msg2"
       }
    ]
    

    To do this, you could simply add the JSON tags to the struct definition, e.g.

    type BadField struct {
        Field string `json:"field"`
        Err   error `json:"error"`
    } 
    

    This would mean calling json.Marshal on a slice of []error which contains BadField instances would result in the JSON above.

    It might be helpful to read more about JSON & Go

    PS Consider if you want your methods to be value or pointer receivers

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥30 BC260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)