当反序列化时转换值

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

Transform values when umarshaling

问题

给定以下代码,是否可以在解组时转换名字?假设我希望始终将其转换为小写,无论实际的 JSON 中是否包含它。

type Person struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
}

func main() {
	jsonText := GetJsonFromSomewhere()
	var v Person
	json.Unmarshal(jsonText, &v)
}

可以在解组时转换名字。你可以使用自定义的解组方法来实现这一点。首先,你需要创建一个结构体类型,该类型包含要解组的字段。然后,你可以为该结构体类型定义一个自定义的 UnmarshalJSON 方法,该方法在解组时会被调用。

下面是一个示例代码,演示如何在解组时将 FirstName 字段转换为小写:

type Person struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
}

func (p *Person) UnmarshalJSON(data []byte) error {
	type Alias Person // 创建一个别名类型,以便在 Unmarshal 过程中使用

	aux := &struct {
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
	}{
		FirstName: strings.ToLower(p.FirstName), // 将 FirstName 转换为小写
	}

	if err := json.Unmarshal(data, &aux); err != nil {
		return err
	}

	*p = Person(*aux) // 将转换后的值赋给原始的 Person 结构体

	return nil
}

func main() {
	jsonText := GetJsonFromSomewhere()
	var v Person
	json.Unmarshal(jsonText, &v)
}

在上面的代码中,我们创建了一个 Alias 类型,它是 Person 类型的别名。在 UnmarshalJSON 方法中,我们首先创建了一个辅助结构体 aux,它具有与 Person 结构体相同的字段。然后,我们将 FirstName 字段转换为小写,并将其赋值给 aux 结构体。接下来,我们使用 json.Unmarshal 将 JSON 数据解组到 aux 结构体中。最后,我们将转换后的值赋给原始的 Person 结构体。

这样,无论实际的 JSON 中 FirstName 字段的值是什么,它都会在解组时被转换为小写。

英文:

Given the code below, is it possible to transform first name while it's being unmarshaled? Say I want to always have it be lowercase whether it is in the actual json or not.

type Person struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
}

func main() {
	jsonText := GetJsonFromSomewhere()
	var v Person
	json.Unmarshal(jsonText, &v)
}

答案1

得分: 4

一种方法是创建一个自定义类型,实现encoding/json包中的Unmarshaler接口。这是该接口的链接。任何实现了Unmarshaler接口的类型都可以在进行JSON解组时用作结构字段的类型。在解组过程中,encoding/json将使用你实现的接口的UnmarshalJSON函数将JSON字节转换为字段类型。

因此,你可以编写一个UnmarshalJSON函数,其中包括将字符串值转换为小写的操作。

以下是一个示例:

type LowerCaseString string

func (l *LowerCaseString) UnmarshalJSON(bytes []byte) error {
	lowerCasedString := strings.ToLower(string(bytes))

	*l = LowerCaseString(lowerCasedString)

	return nil
}

然后,在用于JSON映射的结构中,你可以使用自定义类型而不是string

type Person struct {
    FirstName LowerCaseString `json:"first_name"`
    LastName  LowerCaseString `json:"last_name"`
}

如果你将JSON解组到此结构中,FirstName和LastName的值将被转换为小写(还要注意,你需要将它们转换回string以将其用作string)。

testJSON := `{"first_name" : "TestFirstNAME", "last_name": "TestLastNAME"}`
var result Person

err := json.Unmarshal([]byte(testJSON), &result)
if err != nil { /*处理错误*/ }

fmt.Println(result.FirstName) // 输出 "testfirstname"

var stringLastName string
stringLastName = string(result.LastName) // 需要将LowerCaseString转换为string类型

fmt.Println(stringLastName) // 输出 "testlastname"

这是在Go Playground上运行上述代码的链接

英文:

One way to do this is to create a custom type that implements the Unmarshaler interface from the encoding/json package. Here's a link to this interface. Any type which implements Unmarshaler can be used as the type of a struct field when doing JSON unmarshalling. When doing the unmarshalling, encoding/json will use your implementation of the interface's UnmarshalJSON function to convert the JSON bytes to the field type.

So you could write an UnmarshalJSON function which includes changing the string values to lowercase.

Here's an example of what that could look like:

type LowerCaseString string

func (l *LowerCaseString) UnmarshalJSON(bytes []byte) error {
	lowerCasedString := strings.ToLower(string(bytes))

	*l = LowerCaseString(lowerCasedString)

	return nil
}

Then, in your struct for JSON mapping, you can use your custom type instead of string:

type Person struct {
    FirstName LowerCaseString `json:"first_name"`
    LastName  LowerCaseString `json:"last_name"`
}

If you unmarshal into this struct, the values of FirstName and LastName will be lowercased (also note that you'll need to type convert them back to string to use them as strings).

testJSON := `{"first_name" : "TestFirstNAME", "last_name": "TestLastNAME"}`
var result Person

err := json.Unmarshal([]byte(testJSON), &result)
if err != nil { /*handle the error*/ }

fmt.Println(result.FirstName) // prints "testfirstname"

var stringLastName string
stringLastName = string(result.LastName) // need to type convert from LowerCaseString to string

fmt.Println(stringLastName) // prints "testlastname"

Here is the above code running in Go Playground.

huangapple
  • 本文由 发表于 2023年1月5日 13:05:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75014040.html
匿名

发表评论

匿名网友

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

确定