Home > Article > Backend Development > How can I reuse a structure from a third-party package while changing the marshalling behavior of individual fields?
php editor Zimo is here to share a tip on how to reuse structures in third-party packages and change the marshalling behavior of a single field. When we use a third-party package, sometimes we need to customize a field in it. This article will introduce a simple method that can achieve this goal through inheritance and overwriting, which can not only reuse the original structure but also meet personalized needs. Next, let’s take a look at the specific implementation method!
Suppose I want to marshal a struct into YAML, and the struct has all of its YAML tags defined, except for one that I want to change. How can I change the behavior of this single field without changing the structure itself? Assume that the structure comes from a third party package.
Here is an example to demonstrate, and my best attempt. It is assumed that the User
structure (and its associated Secret
structure) come from a third-party package, so we cannot modify them.
package main import ( "fmt" "gopkg.in/yaml.v2" ) type User struct { Email string `yaml:"email"` Password *Secret `yaml:"password"` } type Secret struct { s string } // MarshalYAML implements the yaml.Marshaler interface for Secret. func (sec *Secret) MarshalYAML() (interface{}, error) { if sec != nil { // Replace `"<secret>"` with `sec.s`, and it gets the desired // behavior. But I can't change the Secret struct: return "<secret>", nil } return nil, nil } func (sec *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error { var st string if err := unmarshal(&st); err != nil { return err } sec.s = st return nil } // My best attempt at the solution: type SolutionAttempt struct { User } func (sol *SolutionAttempt) MarshalYAML() (interface{}, error) { res, err := yaml.Marshal( struct { // I don't like having to repeat all these fields from User: Email string `yaml:"email"` Password string `yaml:"password"` }{ Email: sol.User.Email, Password: sol.User.Password.s, }, ) if err != nil { return nil, err } return string(res), nil } func main() { user := &User{} var data = ` email: [email protected] password: asdf ` err := yaml.Unmarshal([]byte(data), user) if err != nil { fmt.Printf("errors! %s", err) return } buf, err := yaml.Marshal(user) if err != nil { fmt.Printf("errors! %s", err) return } // Without touching User or Secret, how can I unmarshall an // instance of User that renders the secret? fmt.Printf("marshalled output:\n%s\n", buf) /////////////////////////////////////////////////////// // attempted solution: /////////////////////////////////////////////////////// sol := &SolutionAttempt{} var data2 = ` user: email: [email protected] password: asdf ` err = yaml.Unmarshal([]byte(data2), sol) if err != nil { fmt.Printf("errors! %s", err) return } buf, err = yaml.Marshal(sol) if err != nil { fmt.Printf("errors! %s", err) return } fmt.Printf("attempted solution marshalled output:\n%s\n", buf) }
Here is the Go Playground link for the above code: https://go.dev/play/p/ojiPv4ylCEq
This is simply not possible.
Your "best attempt" is the right path.
The above is the detailed content of How can I reuse a structure from a third-party package while changing the marshalling behavior of individual fields?. For more information, please follow other related articles on the PHP Chinese website!