Determine whether the interface-type field of struct is set

PHPz
Release: 2024-02-09 18:27:08
forward
655 people have browsed it

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
   ...
}
Copy after login

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{} }
Copy after login

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
Copy after login

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
    }
}
Copy after login

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)
}
Copy after login

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}
Copy after login

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!

Related labels:
source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!