Go - Composing Structs from Other Structs

发布时间 2023-10-07 15:54:53作者: ZhangZhihuiAAA

Problem: You want a struct that has data and methods of another struct.

 

Solution: Embed an unnamed struct within another struct. The outer struct will gain the data and methods of the inner struct.

 

Inheritance is not the only mechanism you can use for these purposes. Another popular mechanism is composition, which allows you to assemble your models from other models instead of inheriting from a superclass. Go implements composition by embedding an unnamed struct within another struct.

Structs can contain named data fields including structs. However, structs can also contain unnamed data fields, including structs. Whenever a struct has an unnamed data field that is a struct, the data fields within that inner struct are promoted to the outer struct:

type   Person   struct   { 
      Id      int 
      Name    string 
      Email   string 
} 

type   Manager   struct   { 
      Person 
} 

mgr   :=   Manager {} 
mgr . Id   =   2 
mgr . Name   =   "Wong  Fei  Hung" 
mgr . Email   =   "feihung@email.com"

In this example, Manager has a single unnamed data field that is of the type Person . The data fields of Person are promoted to mgr and you can access them directly, without referencing Person at all.

If you try to put mgr through to fmt.Println , you will see this:

{{2  Wong  Fei  Hung  feihung@email.com}}

Notice the double braces {{}} used. This tells you that there is an inner struct instance.

The same rules for exported fields apply here as well — capitalized variable names indicate the fields are exported, while lowercase variable names indicate they are not.

How about methods? They are also promoted to the outer struct:

func   ( person   Person )   Work ()   { 
      fmt . Print ( "Working  hard  ...  " ) 
} 

mgr . Work ()

You can call the Work method directly on mgr because the methods associated with Person are promoted to be available on Manager as well.

This also means any interfaces that Person satisfies, Manager also satisfies:

type   Worker   interface   { 
      Work () 
} 

func   Pay ( worker   Worker )   { 
      worker . Work () 
      fmt . Println ( "and  getting  paid!" ) 
} 

Pay ( mgr )

Since Person satisfies the Worker interface, this means Manager also satisfies the Worker interface and therefore you can pass an instance of Manager to the Pay function.