在Go语言中,一个明确定义的类型的JSON编组是否可能失败?

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

In Go, can JSON marshaling of a well-defined type ever fail?

问题

给定以下代码:

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type Employee struct {
	Id int "json:id"
}

func main() {
	b, err := json.Marshal(&Employee{Id: 2})
	if err != nil {
		log.Fatal("Couldn't marshal the Employee")
	}

	fmt.Println(string(b))
}

在这种情况下,由于Employee结构已经定义好,可以可靠地使用_占位符忽略错误检查吗?从理论上讲,它应该永远不会失败,所以问题是忽略这种类型的错误并节省一些样板式的错误检查是否是一个好的做法?

忽略错误的代码如下:

package main

import (
	"encoding/json"
	"fmt"
)

type Employee struct {
	Id int "json:id"
}

func main() {
	b, _ := json.Marshal(&Employee{Id: 2})
	fmt.Println(string(b))
}

请注意,忽略错误可能会导致潜在的问题,因为你无法得知是否发生了错误。这种做法适用于你确信不会发生错误的情况下,但在一般情况下,建议对错误进行适当的处理和检查。

英文:

Given the following code:

<!-- language: lang-golang -->

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
)

type Employee struct {
	Id int &quot;json:id&quot;
}

func main() {
	b, err := json.Marshal(&amp;Employee{Id: 2})
	if err != nil {
		log.Fatal(&quot;Couldn&#39;t marshal the Employee&quot;)
	}

	fmt.Println(string(b))
}

Can checking for the error be reliably ignored using the _ placeholder since the Employee struct is well defined. Theoretically it should never fail, so begs the question is it a good practice to ignore this type of error and save a little on this type of boilerplate error checking?

Ignoring would look like so:

<!-- language: lang-golang -->

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
)

type Employee struct {
	Id int &quot;json:id&quot;
}

func main() {
	b, _ := json.Marshal(&amp;Employee{Id: 2})
	fmt.Println(string(b))
}

答案1

得分: 7

错误处理和Go

> 正确的错误处理是良好软件的基本要求。


通常情况下,你的代码不会出错。但是如果用户将以下MarshalJSON方法添加到你的类型中,它会出错:

func (t *Employee) MarshalJSON() ([]byte, error) {
    if t.Id == 2 {
        return nil, fmt.Errorf("禁止的 Id = %d", t.Id)
    }
    data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
    return data, nil
}

这段代码可以编译通过,但是故意为了Id == 2而出错(Go Playground):

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, err := json.Marshal(&Employee{Id: 2})
    if err != nil {
        log.Fatal("无法编组 Employee", err)
    }

    fmt.Println(string(b))
}

func (t *Employee) MarshalJSON() ([]byte, error) {
    if t.Id == 2 {
        return nil, fmt.Errorf("禁止的 Id = %d", t.Id)
    }
    data := []byte(fmt.Sprintf(`{"Id":%d}`, t.Id))
    return data, nil
}

同样,这段代码可以编译通过,但是会出错(Go Playground):

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Employee struct {
    Id int "json:id"
}

func main() {
    b, err := json.Marshal(&Employee{Id: 2})
    if err != nil {
        log.Fatal("无法编组 Employee")
    }

    fmt.Println(string(b))
}

func (t Employee) MarshalJSON() ([]byte, error) {
    data := []byte(fmt.Sprint(t))
    return data, nil
}
英文:

Error handling and Go:

> Proper error handling is an essential requirement of good software.


Normally your code won't fail. but if user Adds this MarshalJSON method reciver to your type, it fails:

<!-- language: lang-golang -->

func (t *Employee) MarshalJSON() ([]byte, error) {
	if t.Id == 2 {
		return nil, fmt.Errorf(&quot;Forbiden Id = %d&quot;, t.Id)
	}
	data := []byte(fmt.Sprintf(`{&quot;Id&quot;:%d}`, t.Id))
	return data, nil
}

This code Compiles, but fails on purpose just for Id == 2 (The Go Playground):

<!-- language: lang-golang -->

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
)

type Employee struct {
	Id int &quot;json:id&quot;
}

func main() {
	b, err := json.Marshal(&amp;Employee{Id: 2})
	if err != nil {
		log.Fatal(&quot;Couldn&#39;t marshal the Employee&quot;, err)
	}

	fmt.Println(string(b))
}

func (t *Employee) MarshalJSON() ([]byte, error) {
	if t.Id == 2 {
		return nil, fmt.Errorf(&quot;Forbiden Id = %d&quot;, t.Id)
	}
	data := []byte(fmt.Sprintf(`{&quot;Id&quot;:%d}`, t.Id))
	return data, nil
}

Also this code Compiles, but fails (The Go Playground):

<!-- language: lang-golang -->

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;log&quot;
)

type Employee struct {
	Id int &quot;json:id&quot;
}

func main() {
	b, err := json.Marshal(&amp;Employee{Id: 2})
	if err != nil {
		log.Fatal(&quot;Couldn&#39;t marshal the Employee&quot;)
	}

	fmt.Println(string(b))
}

func (t Employee) MarshalJSON() ([]byte, error) {
	data := []byte(fmt.Sprint(t))
	return data, nil
}

答案2

得分: 0

你可以随时编写自己的“包装器”包,以组合可能成为样板代码的行为。例如,如果你已经设置了一个日志系统,你可以构建一个类似下面的小包:

package json
import (
  "encoding/json"
  "log"
)
func TryMarshal(v interface{}) []byte {
  b, err := json.Marshal(v)
  if err != nil {
    log.Println(err)
    return nil
  }
  return b
}

这个包提供了一个名为TryMarshal的函数,用于将给定的数据结构转换为JSON格式的字节数组。如果转换过程中出现错误,它会将错误信息记录到日志中,并返回nil

英文:

You can always write your own "wrapper" packages to compose behavior that might otherwise be boilerplate. For example, if you have a logging system set up, you might build a small package that looks like:

package json
import (
  &quot;encoding/json&quot;
  &quot;log&quot;
)
func TryMarshal(v interface{}) []byte {
  b, err := json.Marshal(v)
  if err != nil {
    log.Println(err)
    return nil
  }
  return b
}

huangapple
  • 本文由 发表于 2016年8月24日 03:11:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/39109003.html
匿名

发表评论

匿名网友

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

确定