Skip to content

reflect: StructTag.Get does not return 1st tag of dynamic structure created with StructOf #66645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ivasylenko opened this issue Apr 2, 2024 · 2 comments

Comments

@ivasylenko
Copy link

Go version

go1.22.0 linux/amd64

Output of go env in your module/workspace:

GO111MODULE='on'
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/ivasylen/.cache/go-build'
GOENV='/home/ivasylen/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/ivasylen/golang/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/ivasylen/guardicore/management/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.0'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/ivasylen/guardicore/management/c2c/go/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1023271956=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I am working with reflection package, creating dynamic structures with reflect.StructOf.
Later on I inspect these structure tags and 1st tag is always missing for any field.
I have simple UT

func TestDynamicStructTags(t *testing.T) {
	field := reflect.StructField{
		Name: "Field",
		Type: reflect.TypeOf(""),
		Tag:  reflect.StructTag("`k1:\"v1\" k2:\"v2\" k3:\"v3\"`"),
	}
	stType := reflect.StructOf([]reflect.StructField{field})
	for i := 0; i < stType.NumField(); i++ {
		var (
			f = stType.Field(i)
		)
		tagsFmt := fmt.Sprintf("%s, %s, %s, %s", f.Tag, f.Tag.Get("k1"), f.Tag.Get("k2"), f.Tag.Get("k3"))
		//assert.Equal(t, "`k1:\"v1\" k2:\"v2\" k3:\"v3\"`, , v2, v3", tagsFmt)
		assert.Equal(t, "`k1:\"v1\" k2:\"v2\" k3:\"v3\"`, v1, v2, v3", tagsFmt)
	}
}

What did you see happen?

In above test, k1 is missing

// k1 is missing
// expected: "`k1:\"v1\" k2:\"v2\" k3:\"v3\"`, v1, v2, v3"
// actual  : "`k1:\"v1\" k2:\"v2\" k3:\"v3\"`, , v2, v3"

What did you expect to see?

I would expect all tags returned, including k1

@ivasylenko ivasylenko changed the title reflect/type.go : struct tag Lookup can not find right tag name reflect/type.go : reflect.StructTag Get does not return 1st tag Apr 2, 2024
@ivasylenko ivasylenko changed the title reflect/type.go : reflect.StructTag Get does not return 1st tag reflect/type.go : reflect.StructTag Get does not return 1st tag of dynamic structure reflect.StructOf Apr 2, 2024
@ivasylenko ivasylenko changed the title reflect/type.go : reflect.StructTag Get does not return 1st tag of dynamic structure reflect.StructOf reflect/type.go : reflect.StructTag Get does not return 1st tag of dynamic structure created with reflect.StructOf Apr 2, 2024
@callthingsoff
Copy link
Contributor

package main

import (
	"fmt"
	"reflect"
)

func main() {
	fmt.Println(reflect.StructTag("k1:\"v1\"").Get("k1"))
	fmt.Println(reflect.StructTag(`k1:"v1"`).Get("k1"))
	fmt.Println(reflect.StructTag("`k1:\"v1\"`").Get("k1"))
	fmt.Println(reflect.StructTag("`k1:\"v1\"`").Get("`k1"))
}
v1
v1

v1

I think maybe you can change the StructTag key.

@dmitshur
Copy link
Member

dmitshur commented Apr 2, 2024

Thanks for reporting. https://pkg.go.dev/reflect#StructTag documentation says:

By convention, tag strings are a concatenation of optionally space-separated key:"value" pairs. Each key is a non-empty string consisting of non-control characters other than space (U+0020 ' '), quote (U+0022 '"'), and colon (U+003A ':'). Each value is quoted using U+0022 '"' characters and Go string literal syntax.

It looks like the provided code is inadvertently defining a key named `k1 rather than k1 as intended due to extra backticks at the start and end of the string, and as callthingsoff's snippet demonstrates, it is possible to access the first key (even if it is named `k1).

Closing since there doesn't appear to be a problem in the reflect package.

CC @golang/runtime.

@dmitshur dmitshur closed this as not planned Won't fix, can't repro, duplicate, stale Apr 2, 2024
@dmitshur dmitshur changed the title reflect/type.go : reflect.StructTag Get does not return 1st tag of dynamic structure created with reflect.StructOf reflect: StructTag.Get does not return 1st tag of dynamic structure created with StructOf Apr 2, 2024
@golang golang locked and limited conversation to collaborators Apr 2, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants