Home  >  Article  >  Backend Development  >  Determine whether the interface-type field of struct is set

Determine whether the interface-type field of struct is set

PHPz
PHPzforward
2024-02-09 18:27:08656browse

Determine whether the interface-type field of struct is set

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!

Question content

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
    }
}

Workaround

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!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete