// Copyright 2021 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package typesimport ()// ----------------------------------------------------------------------------// API// A Struct represents a struct type.typeStructstruct {fields []*Var// fields != nil indicates the struct is set up (possibly with len(fields) == 0)tags []string// field tags; nil if there are no tags}// NewStruct returns a new struct with the given fields and corresponding field tags.// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be// only as long as required to hold the tag with the largest index i. Consequently,// if no field has a tag, tags may be nil.func ( []*Var, []string) *Struct {varobjsetfor , := range {if .name != "_" && .insert() != nil {panic("multiple fields with the same name") } }iflen() > len() {panic("more tags than fields") } := &Struct{fields: , tags: } .markComplete()return}// NumFields returns the number of fields in the struct (including blank and embedded fields).func ( *Struct) () int { returnlen(.fields) }// Field returns the i'th field for 0 <= i < NumFields().func ( *Struct) ( int) *Var { return .fields[] }// Tag returns the i'th field tag for 0 <= i < NumFields().func ( *Struct) ( int) string {if < len(.tags) {return .tags[] }return""}func ( *Struct) () Type { return }func ( *Struct) () string { returnTypeString(, nil) }// ----------------------------------------------------------------------------// Implementationfunc ( *Struct) () {if .fields == nil { .fields = make([]*Var, 0) }}func ( *Checker) ( *Struct, *ast.StructType) { := .Fieldsif == nil { .markComplete()return }// struct fields and tagsvar []*Varvar []string// for double-declaration checksvarobjset// current field typ and tagvarTypevarstring := func( *ast.Ident, bool, token.Pos) {if != "" && == nil { = make([]string, len()) }if != nil { = append(, ) } := .Name := NewField(, .pkg, , , )// spec: "Within a struct, non-blank field names must be unique."if == "_" || .declareInSet(&, , ) { = append(, ) .recordDef(, ) } }// addInvalid adds an embedded field of invalid type to the struct for // fields with errors; this keeps the number of struct fields in sync // with the source as long as the fields are _ or have different names // (issue #25627). := func( *ast.Ident, token.Pos) { = Typ[Invalid] = "" (, true, ) }for , := range .List { = .varType(.Type) = .tag(.Tag)iflen(.Names) > 0 {// named fieldsfor , := range .Names { (, false, .Pos()) } } else {// embedded field // spec: "An embedded type must be specified as a type name T or as a // pointer to a non-interface type name *T, and T itself may not be a // pointer type." := .Type.Pos() := embeddedFieldIdent(.Type)if == nil { .invalidAST(.Type, "embedded field type %s has no name", .Type) = ast.NewIdent("_") .NamePos = (, )continue } (, true, )// Because we have a name, typ must be of the form T or *T, where T is the name // of a (named or alias) type, and t (= deref(typ)) must be the type of T. // We must delay this check to the end because we don't want to instantiate // (via under(t)) a possibly incomplete type.// for use in the closure below := := .Type .later(func() { , := deref()switch u := under().(type) {case *Basic:if == Typ[Invalid] {// error was reported beforereturn }// unsafe.Pointer is treated like a regular pointerif .kind == UnsafePointer { .error(, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") }case *Pointer: .error(, _InvalidPtrEmbed, "embedded field type cannot be a pointer")case *Interface:ifisTypeParam() {// The error code here is inconsistent with other error codes for // invalid embedding, because this restriction may be relaxed in the // future, and so it did not warrant a new error code. .error(, _MisplacedTypeParam, "embedded field type cannot be a (pointer to a) type parameter")break }if { .error(, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") } } }).describef(, "check embedded type %s", ) } } .fields = .tags = .markComplete()}func ( ast.Expr) *ast.Ident {switch e := .(type) {case *ast.Ident:returncase *ast.StarExpr:// *T is valid, but **T is notif , := .X.(*ast.StarExpr); ! {return (.X) }case *ast.SelectorExpr:return .Selcase *ast.IndexExpr:return (.X)case *ast.IndexListExpr:return (.X) }returnnil// invalid embedded field}func ( *Checker) ( *objset, token.Pos, Object) bool {if := .insert(); != nil { .errorf(atPos(), _DuplicateDecl, "%s redeclared", .Name()) .reportAltDecl()returnfalse }returntrue}func ( *Checker) ( *ast.BasicLit) string {if != nil {if .Kind == token.STRING {if , := strconv.Unquote(.Value); == nil {return } } .invalidAST(, "incorrect tag syntax: %q", .Value) }return""}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)