查看是否支持泛型
Go语言的泛型支持始于Go 1.18版本。
在这个版本中,Go核心团队进行了自Go语言开源以来最大的一次语法特性变更,引入了对使用参数化类型的泛型代码的支持。
查看版本
在不支持泛型的版本里,泛型编程使用interface{}实现。
简单的JSON转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package test
import ( "encoding/json" "fmt" "z-wiki/utils" )
type Person struct { Name string `json:"name"` Age int `json:"age"` }
func Json2Str() { person := Person{Name: "Alice", Age: 30} jsonData, err := json.Marshal(person) if err != nil { fmt.Println("转换失败:", err) return } jsonString := string(jsonData) fmt.Println("Json2Str:", jsonString) }
func Str2Json() { str := `{"Name": "Alice", "Age": 30}` var person Person err := json.Unmarshal([]byte(str), &person) if err != nil { fmt.Println("转换失败:", err) return } fmt.Printf("Str2Json:%+v\n", person) }
|
带泛型的JSON转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package test
import ( "encoding/json" "fmt" "z-wiki/utils" )
type ResultVo[T any] struct { Code int `json:"code"` Msg string `json:"msg"` Obj T `json:"obj"` }
type Person struct { Name string `json:"name"` Age int `json:"age"` }
func Str2Json2() { str := `{ "code": 0, "msg": "success", "obj": { "Name": "Alice", "Age": 30 } }` var result ResultVo[Person] err := json.Unmarshal([]byte(str), &result) if err != nil { fmt.Println("转换失败:", err) return } fmt.Printf("Str2Json2:%+v\n", result) }
|
JSON转换工具类
工具类
utils/json_utils.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package utils
import ( "encoding/json" )
func ObjToStr(value interface{}) (string, error) { meta, err := json.Marshal(value) return string(meta), err }
func StrToObj(meta string, result interface{}) error { return json.Unmarshal(StringToBytes(meta), result) }
func StringToBytes(value string) []byte { return []byte(value) }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| package test
import ( "fmt" "z-wiki/utils" )
type ResultVo[T any] struct { Code int `json:"code"` Msg string `json:"msg"` Obj T `json:"obj"` }
type Person struct { Name string `json:"name"` Age int `json:"age"` }
func Obj2Str() { result := ResultVo[Person]{Code: 0, Msg: "success", Obj: Person{Name: "Alice", Age: 30}} jsonString, err := utils.ObjToStr(result) if err != nil { return } fmt.Println("Obj2Str:", jsonString) }
func Obj2Str2() { result := []Person{Person{Name: "张三", Age: 18}, Person{Name: "李四", Age: 30}} jsonString, err := utils.ObjToStr(result) if err != nil { return } fmt.Println("Obj2Str2:", jsonString) }
func Str2Obj() { str := `{ "code": 0, "msg": "success", "obj": { "Name": "Alice", "Age": 30 } }` var result ResultVo[Person] err := utils.StrToObj(str, &result) if err != nil { return } fmt.Printf("Str2Obj:%+v\n", result) }
func Str2Obj2() { str := `[ { "Name": "张三", "Age": 30 }, { "Name": "李四", "Age": 18 } ]`
var result []Person err := utils.StrToObj(str, &result) if err != nil { fmt.Println(err) return } fmt.Printf("Str2Obj2:%+v\n", result) }
|
JSON转换工具类(泛型)
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package utils
import ( "encoding/json" )
func ObjToJson[T any](obj T) (string, error) { meta, err := json.Marshal(obj) return string(meta), err }
func JsonToObj[T any](str string) (T, error) { var result T err := json.Unmarshal(StringToBytes(str), &result) return result, err }
func StringToBytes(str string) []byte { return []byte(str) }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| package test
import ( "fmt" "z-wiki/utils" )
type ResultVo[T any] struct { Code int `json:"code"` Msg string `json:"msg"` Obj T `json:"obj"` }
type Person struct { Name string `json:"name"` Age int `json:"age"` }
func Obj2Str() { result := ResultVo[Person]{Code: 0, Msg: "success", Obj: Person{Name: "Alice", Age: 30}} jsonString, err := utils.ObjToJson[ResultVo[Person]](result) if err != nil { return } fmt.Println("Obj2Str:", jsonString) }
func Obj2Str2() { result := []Person{Person{Name: "张三", Age: 18}, Person{Name: "李四", Age: 30}} jsonString, err := utils.ObjToJson[[]Person](result) if err != nil { return } fmt.Println("Obj2Str2:", jsonString) }
func Str2Obj() { str := `{ "code": 0, "msg": "success", "obj": { "Name": "Alice", "Age": 30 } }` result, err := utils.JsonToObj[ResultVo[Person]](str) if err != nil { fmt.Println(err) return } fmt.Printf("Str2Obj:%+v\n", result) }
func Str2Obj2() { str := `[ { "Name": "张三", "Age": 30 }, { "Name": "李四", "Age": 18 } ]`
result, err := utils.JsonToObj[[]Person](str) if err != nil { fmt.Println(err) return } fmt.Printf("Str2Obj2:%+v\n", result) }
|
main_test.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package test
import ( "testing" )
func Test01(t *testing.T) { Obj2Str() Obj2Str2()
Str2Obj() Str2Obj2() }
|
两者结合
这里对象转字符串一般不会报错,所以直接返回的字符串,不再返回错误。
对象转字符串不再传入原类型,方便调用。
字符串转对象依旧使用的泛型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package utils
import ( "encoding/json" )
func ObjToJson(value interface{}) string { meta, err := json.Marshal(value) if err != nil { return "" } return string(meta) }
func JsonToObj[T any](str string) (T, error) { var result T err := json.Unmarshal(StringToBytes(str), &result) return result, err }
func StringToBytes(str string) []byte { return []byte(str) }
|
知识点
interface{}
在 Go 语言中,interface{} 是一种空接口类型(empty interface),也被称为“空接口”。
空接口可以接受任何类型的值,因为它不限制其包含的值的类型。换句话说,空接口不包含任何方法签名,因此可以表示任何类型的值。
在 Go 中,空接口的定义如下:
1
| type emptyInterface interface{}
|
通过空接口,可以存储任何值,因为任何值都满足空接口的要求。这使得空接口在处理未知类型、泛型编程或者需要接受任意类型参数的情况下非常有用。
下面是一个简单的示例,展示了如何使用空接口来接受任意类型的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package main
import "fmt"
func describe(i interface{}) { fmt.Printf("(%v, %T)\n", i, i) }
func main() { var i interface{}
i = 42 describe(i)
i = "hello" describe(i)
i = true describe(i) }
|
在上面的示例中,describe 函数接受一个空接口参数,并打印出该参数的值和类型。
在 main 函数中,我们使用不同类型的值调用 describe 函数来演示空接口的灵活性。
总之,空接口 interface{} 是一种特殊的接口类型,在 Go 语言中起到了非常重要的作用,它允许我们在不知道具体类型的情况下处理各种值。
结构体
上面JSON转换的时候结构体是这样写的:
1 2 3 4
| type Person struct { Name string `json:"name"` Age int `json:"age"` }
|
在 Go 语言中,结构体(struct)中的字段类型后面的 json:"name" 是用于定义字段的 JSON 编码/解码时的特殊标签(tag)。
这种标签的作用是为结构体字段添加额外的元信息,用于在编码和解码 JSON 数据时指定字段的名称、忽略字段等属性。
在给定的示例中,json:"name" 和 json:"age" 是用于指定字段在 JSON 编码/解码过程中对应的名称。
这意味着当使用 Go 的 encoding/json 包编码该结构体实例时,Name 字段会被编码为 JSON 对象的 name 属性,Age 字段会被编码为 JSON 对象的 age 属性。
以下是一个示例说明如何使用结构体标签进行 JSON 编码/解码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package main
import ( "encoding/json" "fmt" )
type Person struct { Name string `json:"name"` Age int `json:"age"` }
func main() { p := Person{"Alice", 30}
jsonData, err := json.Marshal(p) if err != nil { fmt.Println("JSON encode error:", err) return }
fmt.Println(string(jsonData))
var p2 Person err = json.Unmarshal(jsonData, &p2) if err != nil { fmt.Println("JSON decode error:", err) return }
fmt.Println(p2) }
|
在上面的示例中,我们定义了一个Person结构体,其中每个字段都有一个类似json:"name"的标签。
使用json.Marshal函数将Person实例编码为 JSON 数据时,编码器会根据这些标签将字段名映射到 JSON 对象中的属性名。
相反,json.Unmarshal函数则依据这些标签将 JSON 数据的属性名映射回结构体的字段。
总之,类型后面的 json:"name" 是结构体字段的标签,用于定义该字段在 JSON 编码/解码过程中的属性。