{"id":1618,"date":"2015-09-16T23:00:16","date_gmt":"2015-09-17T04:00:16","guid":{"rendered":"http:\/\/unitstep.net\/?p=1618"},"modified":"2015-09-16T23:02:13","modified_gmt":"2015-09-17T04:02:13","slug":"golang-promoted-methods-method-sets-and-embedded-types","status":"publish","type":"post","link":"https:\/\/unitstep.net\/blog\/2015\/09\/16\/golang-promoted-methods-method-sets-and-embedded-types\/","title":{"rendered":"Golang: Promoted methods, method sets and embedded types"},"content":{"rendered":"
In Go, interfaces are implemented implicitly by ensuring that the implementing type’s method set contains all the methods of the interface. That is, if a type A contains a method set that is a superset of interface I’s method set, then type A implements interface I<\/a>.<\/p>\n This seems pretty straightforward, but can get a little convoluted when dealing with struct types that have embedded\/anonymous fields.<\/p>\n <\/p>\n In Go, a struct can have an embedded or anonymous field; the embedded type is specified just with the type name, and can either be a value type or a pointer to a such a type. For example, in the following code, the Embedding is composition, not inheritance<\/a>, but Go also does something called “promotion”, whereby the fields or methods of embedded types become available on the outer\/embedding type. This provides a sort of automatic delegation and gives the pseudo-impression of “inheritance”, though it’s probably best not think of it that way. Here’s what the Go spec<\/a> says about promotion:<\/p>\n A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.<\/p>\n Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.<\/p><\/blockquote>\n This means that for the above example, we can call the methods defined on the embedded types { However, these methods are not<\/strong> included in the method set for the value type Embedded in plain sight<\/h2>\n
BossManager<\/code> struct embeds the types
Boss<\/code> and
Manager<\/code>:<\/p>\n
type Boss struct {}\r\nfunc (b *Boss) AssignWork() {\r\n\tfmt.Println(\"Boss assigned work\")\r\n}\r\n\r\ntype Manager struct {}\r\nfunc (m *Manager) PreparePowerPoint() {\r\n\tfmt.Println(\"PowerPoint prepared\")\r\n}\r\n\r\ntype BossManager struct {\r\n\tBoss\r\n\tManager\r\n}<\/code><\/pre>\n
Boss, <\/code>
Manager<\/code>} as if they were defined on
BossManager<\/code> itself:<\/p>\n
bm := BossManager{}\r\n\r\n\/\/ Both methods (which use pointer receivers) have been promoted to BossManager.\r\nbm.AssignWork() \/\/ \"Boss assigned work\"\r\nbm.PreparePowerPoint() \/\/ \"PowerPoint prepared\"<\/code><\/pre>\n
BossManager<\/code>. This is because they are defined with pointer receivers, not value receivers.<\/p>\n