Tags: #go #golang #struct #embedding #embed
This shows struct and interface embedding with basic custom objects to hopefully more easily explain how things work.
See https://gist.github.com/Integralist/b2e87acad7fdf354ade3250dcb31c168#file-1-md for an explanation.
This shows struct and interface embedding with real golang stdlib object.
This is so in a ‘dev’ environment we can return an object that calls a ‘mock’ method, while in production the returned object will be different and so it won’t call that method.
package main
import (
"fmt"
)
type foo struct {
bar string
}
func (f *foo) baz() {
fmt.Println("baz called and bar =", f.bar)
}
type x interface {
baz()
}
/*
// struct embedding example
type bar struct {
*foo
}
*/
// interface embedding example
type bar struct {
x
}
func newBar() *bar {
return &bar{&foo{"abc"}}
// you can also be explicit and specify the 'field', which is x
//
// e.g.
// return &bar{x: &foo{"abc"}}
//
// typically the field is the last segment of the struct/interface
//
// e.g.
// *redis.Client (struct: the field would be Client)
// io.Writer (interface: the field would be Writer)
//
// with either a struct embedded or an interface embedded
// you can call the embedded functions directly AND indirectly
//
// e.g. example where we embedded *redis.Client we can call its TTL() function like so...
// b.TTL()
// b.Client.TTL()
//
// e.g. example where we embedded x interface we can call its baz() function like so...
// b.baz()
// b.x.baz()
}
func doSomething(a x) {
fmt.Println("doSomething called")
a.baz()
}
func main() {
b := newBar()
b.baz()
// b.foo.baz() // only works when a struct is embedded inside a struct, not when an interface is embedded
// b.x.baz() // works when interface is embedded inside a struct as 'x' is the name of the interface
fmt.Printf("%+v\n", b)
doSomething(b)
}
package main
import (
"compress/gzip"
"fmt"
"os"
)
type gzipWriterWrapper struct {
*gzip.Writer // what identifier is this exposed as? see below!
foo string
}
type writerThing struct {
io.Writer
foo string
}
func main() {
g := gzipWriterWrapper{gzip.NewWriter(os.Stdout), "bar"}
fmt.Printf("%+v\n", g) // {Writer:0x448460 foo:bar}
wt := writerThing{foo: "bar"}
fmt.Printf("%+v\n", g) // {Writer:nil foo:bar}
// notice you still need to provide an _implementation_ of io.Writer
}
/*
gzip.Writer methods can be accessed either directly or indirectly...
- indirectly: g.Write(...)
- directly: g.Writer.Write(...)
*/
package main
import (
"fmt"
)
type foo struct {
bar string
}
func (f *foo) baz() {
fmt.Println("baz called and bar =", f.bar)
}
type mock struct {
*bar
}
func (m *mock) mocker() {
fmt.Println("mocker called")
}
// struct embedding example
type bar struct {
*foo
}
type basicRequirements interface {
baz()
}
func newBar(mocked bool) basicRequirements {
if mocked {
fmt.Println("create instance of bar that has mock method")
return &mock{&bar{&foo{"abc"}}}
}
fmt.Println("create instance of bar that does NOT have mock method")
return &bar{&foo{"abc"}}
}
func main() {
b := newBar(true)
b.baz()
// careful if calling newBar(false) as this assertion will break
basserted := b.(*mock)
basserted.mocker()
fmt.Printf("%+v\n", b)
}