Golang中结构体字段标签与reflect.StructTag.Get不兼容问题:结构体标签对语法错误解析

Golang中结构体字段标签与reflect.StructTag.Get不兼容问题:结构体标签对语法错误解析 以下是我的代码:

package main

import (
	"bytes"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type User struct {
	Name string `name`
	Age  int64  `age`
}

func main() {
	var u User = User{"bob", 10}

	res, err := JSONEncode(u)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(res))

}

func JSONEncode(v interface{}) ([]byte, error) {
	refObjVal := reflect.ValueOf(v)
	refObjTyp := reflect.TypeOf(v)
	buf := bytes.Buffer{}
	if refObjVal.Kind() != reflect.Struct {
		return buf.Bytes(), fmt.Errorf(
			"val of kind %s is not supported",
			refObjVal.Kind(),
		)
	}
	buf.WriteString("{")
	pairs := []string{}
	for i := 0; i < refObjVal.NumField(); i++ {
		structFieldRefObj := refObjVal.Field(i)
		structFieldRefObjTyp := refObjTyp.Field(i)

		switch structFieldRefObj.Kind() {
		case reflect.String:
			strVal := structFieldRefObj.Interface().(string)
			pairs = append(pairs, `"`+string(structFieldRefObjTyp.Tag)+`":"`+strVal+`"`)
		case reflect.Int64:
			intVal := structFieldRefObj.Interface().(int64)
			pairs = append(pairs, `"`+string(structFieldRefObjTyp.Tag)+`":`+strconv.FormatInt(intVal, 10))
		default:
			return buf.Bytes(), fmt.Errorf(
				"struct field with name %s and kind %s is not supprted",
				structFieldRefObjTyp.Name,
				structFieldRefObj.Kind(),
			)
		}
	}

	buf.WriteString(strings.Join(pairs, ","))
	buf.WriteString("}")

	return buf.Bytes(), nil
}

它运行得很好,输出如下:

{"name":"bob","age":10}

但在VS Code中,它给我显示了以下问题:

enter image description here

可能是什么问题?

注意 我知道结构体标签应该是 key:"value" 的形式,例如 field:"name",并且尝试了:

type User struct {
    Name string `field:"name"`
    Age  int64  `field:"age"`
}

但这次的输出是错误的,我得到了:

{"field:"name"":"bob","field:"age"":10}

更多关于Golang中结构体字段标签与reflect.StructTag.Get不兼容问题:结构体标签对语法错误解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

您必须使用正确的语法(成对的引号和分号)来指定标签:

type User struct {
	Name string `name:"welcome"`
	Age  int64  `age:"hello"`
}

favicon.ico

reflect package - reflect - Go Packages

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types.

更多关于Golang中结构体字段标签与reflect.StructTag.Get不兼容问题:结构体标签对语法错误解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我在 Stack Overflow 上找到了答案,并复制到这里供社区参考。

请注意,这只是一个警告,提示你没有遵循约定。正如你已经知道的,代码可以编译、运行并输出你想要的结果:Go Playground - The Go Programming Language

要避免这个警告,可以禁用你的 linter,或者,更好的做法是遵循约定,在结构体标签中使用 key:"value",然后通过 Get 方法提取值:Go Playground - The Go Programming Language


pkg.go.dev

reflect package - reflect - Go Packages

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types.

StructTag 是结构体字段中的标签字符串。

按照约定,标签字符串是由可选的、以空格分隔的 key:“value” 对连接而成的。 每个 key 都是一个非空字符串,由除空格 (U+0020 ’ ')、引号 (U+0022 ‘"’) 和冒号 (U+003A ‘:’) 之外的非控制字符组成。每个 value 都使用 U+0022 ‘"’ 字符和 Go 字符串字面量语法进行引用。

你的代码存在两个关键问题:

  1. 结构体标签语法错误:你的标签缺少引号,应该是反引号包裹的键值对形式
  2. 标签解析方式错误:直接使用string(structFieldRefObjTyp.Tag)会输出完整的标签字符串,而不是特定的键值

以下是修正后的代码:

package main

import (
	"bytes"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type User struct {
	Name string `json:"name"`
	Age  int64  `json:"age"`
}

func main() {
	var u User = User{"bob", 10}

	res, err := JSONEncode(u)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(res))
}

func JSONEncode(v interface{}) ([]byte, error) {
	refObjVal := reflect.ValueOf(v)
	refObjTyp := reflect.TypeOf(v)
	buf := bytes.Buffer{}
	if refObjVal.Kind() != reflect.Struct {
		return buf.Bytes(), fmt.Errorf(
			"val of kind %s is not supported",
			refObjVal.Kind(),
		)
	}
	buf.WriteString("{")
	pairs := []string{}
	for i := 0; i < refObjVal.NumField(); i++ {
		structFieldRefObj := refObjVal.Field(i)
		structFieldRefObjTyp := refObjTyp.Field(i)

		// 使用Get方法获取特定键的值
		tagValue := structFieldRefObjTyp.Tag.Get("json")
		if tagValue == "" {
			// 如果没有json标签,使用字段名
			tagValue = structFieldRefObjTyp.Name
		}

		switch structFieldRefObj.Kind() {
		case reflect.String:
			strVal := structFieldRefObj.Interface().(string)
			pairs = append(pairs, `"`+tagValue+`":"`+strVal+`"`)
		case reflect.Int64:
			intVal := structFieldRefObj.Interface().(int64)
			pairs = append(pairs, `"`+tagValue+`":`+strconv.FormatInt(intVal, 10))
		default:
			return buf.Bytes(), fmt.Errorf(
				"struct field with name %s and kind %s is not supported",
				structFieldRefObjTyp.Name,
				structFieldRefObj.Kind(),
			)
		}
	}

	buf.WriteString(strings.Join(pairs, ","))
	buf.WriteString("}")

	return buf.Bytes(), nil
}

输出:

{"name":"bob","age":10}

关键修改:

  1. 使用正确的结构体标签语法:`json:"name"`
  2. 使用structFieldRefObjTyp.Tag.Get("json")获取特定键的值,而不是直接转换整个标签字符串
  3. 添加了标签值为空时的回退逻辑,使用字段名作为JSON键

这样既解决了VS Code的语法检查警告,也正确解析了结构体标签。

回到顶部