« Back to Index

[Golang Struct and Interface Embedding Examples]

View original Gist on GitHub

Tags: #go #golang #struct #embedding #embed

1. Examples.md

1. simplified ‘reduced’ examples

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.

2. real example with gzip.NewWriter

This shows struct and interface embedding with real golang stdlib object.

3. we want to return two different objects (with different methods)

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.

Golang Struct and Interface Embedding Example 1.go

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)
}

Golang Struct and Interface Embedding Example 2.go

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(...)
*/

Golang Struct and Interface Embedding Example 3.go

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)
}