php editor Xiaoxin is here to share a tip on determining whether the interface-type field of the struct is set. In the Go language, the struct type can implement multiple interfaces. By determining whether the interface-type field is set, we can easily determine whether a struct implements a specific interface. This technique is very practical. It can accurately determine the type of object in the code and handle it accordingly. Next, let’s take a look at the specific implementation method!
Given a structure, its fields belong to the interface type:
type a interface { foo() } type b interface { bar() } type container struct { fielda a fieldb b ... }
And the structures that implement these interfaces:
type a struct {} func (*a) foo() {} func newa() *a { return &a{} } type b struct {} func (*b) bar() {} func newb() *b { return &b{} }
And the code that creates a container
instance without explicitly setting all fields:
c := &container{} c.fielda = newa() // c.fieldb = newb() // <-- fieldb not explicitly set
Using reflection, how to detect fields that are not explicitly set?
Checking the value of fieldb at runtime, vscode happily reports the value as nil
. Likewise, trying to call c.fieldb.bar() will panic due to a nil pointer dereference. But reflection doesn't let you test isnil, nor iszero returns true:
func validateContainer(c *container) { tC := reflect.TypeOf(*c) for i := 0; i < tC.NumField(); i++ { reflect.ValueOf(tC.Field(i)).IsNil() // panics reflect.ValueOf(tC.Field(i)).IsZero() // always false reflect.ValueOf(tC.Field(i)).IsValid() // always true } }
You should check the field for reflect.valueof(*c)
instead of reflect.typeof(*c)
.
package main import ( "fmt" "reflect" ) func validatecontainer(c *container) { tc := reflect.typeof(*c) vc := reflect.valueof(*c) for i := 0; i < vc.numfield(); i++ { if f := vc.field(i); f.kind() == reflect.interface { fmt.printf("%v: isnil: %v, iszero: %v, isvalid: %v\n", tc.field(i).name, f.isnil(), f.iszero(), f.isvalid(), ) } } // tc.field(i) returns a reflect.structfield that describes the field. // it's not the field itself. fmt.printf("%#v\n", reflect.valueof(tc.field(0))) } type a interface{ foo() } type b interface{ bar() } type container struct { fielda a fieldb b } type a struct{} func (*a) foo() {} func newa() *a { return &a{} } func main() { c := &container{} c.fielda = newa() validatecontainer(c) }
Output:
FieldA: IsNil: false, isZero: false, IsValid: true FieldB: IsNil: true, isZero: true, IsValid: true reflect.StructField{Name:"FieldA", PkgPath:"", Type:(*reflect.rtype)(0x48de20), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false}
The above is the detailed content of Determine whether the interface-type field of struct is set. For more information, please follow other related articles on the PHP Chinese website!