Skip to content

Instantly share code, notes, and snippets.

@bojand
Last active April 7, 2019 17:18
Show Gist options
  • Save bojand/ad0ee5f25c86fdc028b1830a62d7ff34 to your computer and use it in GitHub Desktop.
Save bojand/ad0ee5f25c86fdc028b1830a62d7ff34 to your computer and use it in GitHub Desktop.
Go interfaces
package main
import (
"bytes"
"fmt"
"io"
"reflect"
)
func do(w io.Writer) {
fmt.Printf("value in interface is nil? %+v\n", reflect.ValueOf(w).IsNil())
switch w.(type) {
case *bytes.Buffer:
{
fmt.Println("w is a buffer pointer")
v := w.(*bytes.Buffer)
if v == nil {
fmt.Println("w is a nil buffer pointer")
} else {
fmt.Println("w is a not-nil buffer pointer")
}
}
case nil:
fmt.Println("w is nil")
default:
fmt.Println("w is something else")
}
}
func main() {
var b *bytes.Buffer
do(b)
fmt.Printf("b is %+v\n", b)
b2 := bytes.NewBuffer(nil)
do(b2)
fmt.Printf("b2 is %+v\n", b)
}
package main
import (
"fmt"
)
type Inner struct {
Name string
}
func (i Inner) String() string {
return i.Name
}
func CreateStringer() fmt.Stringer {
return &Inner{"Bob2"}
}
type Outer struct {
Memb interface{}
}
func main() {
i := CreateStringer()
o := Outer{i} // does not work with &i
if m, ok := o.Memb.(fmt.Stringer); ok {
fmt.Printf("Satisfies. Name: %s\n", m)
} else {
fmt.Println("Not a stringer")
}
}
package main
import (
"log"
"strings"
)
type Fooer interface {
Foo()
}
type A struct {
Name string
}
func (a A) Foo() {
log.Printf("A.Foo(): %s\n", a.Name)
}
type B struct {
Name string
}
func (b *B) Foo() {
log.Printf("B.Foo(): %s\n", b.Name)
}
type C struct {
Name string
}
func (c *C) Foo() {
c.Name = strings.ToUpper(c.Name)
log.Printf("C.Foo(): %s\n", c.Name)
}
func DoFoo(f Fooer) {
f.Foo()
}
func CreateFooer(t string, name string) Fooer {
if t == "a" {
return &A{name}
} else if t == "b" {
return &B{name}
}
return &C{name}
}
func main() {
a := A{"AName"}
b := B{"BName"}
c := C{"CName"}
log.Printf("a: %+v\n", a)
log.Printf("b: %+v\n", b)
log.Printf("c: %+v\n", c)
DoFoo(a)
DoFoo(&a)
// DoFoo(b)
// ^ cannot use b (type B) as type Fooer in argument to DoFoo: B does not implement Fooer (Foo method has pointer receiver)
DoFoo(&b)
// DoFoo(c)
// ^ cannot use c (type C) as type Fooer in argument to DoFoo: C does not implement Fooer (Foo method has pointer receiver)
DoFoo(&c)
log.Printf("a: %+v\n", a)
log.Printf("b: %+v\n", b)
log.Printf("c: %+v\n", c)
aC := CreateFooer("a", "ANameC")
bC := CreateFooer("b", "BNameC")
cC := CreateFooer("c", "CNameC")
log.Printf("aC: %+v\n", aC)
log.Printf("bC: %+v\n", bC)
log.Printf("cC: %+v\n", cC)
DoFoo(aC)
// DoFoo(&aC)
// ^ cannot use &aC (type *Fooer) as type Fooer in argument to DoFoo: *Fooer is pointer to interface, not interface
DoFoo(bC)
// DoFoo(&bC)
// ^ cannot use &bC (type *Fooer) as type Fooer in argument to DoFoo: *Fooer is pointer to interface, not interface
DoFoo(cC)
// DoFoo(&cC)
// ^ cannot use &cC (type *Fooer) as type Fooer in argument to DoFoo: *Fooer is pointer to interface, not interface
log.Printf("aC: %+v\n", aC)
log.Printf("bC: %+v\n", bC)
log.Printf("cC: %+v\n", cC)
}
package main
import (
"fmt"
)
type Fooer interface {
Foo() string
// Bar() string
// if we uncomment this function
// MyType will no longer satisfy the interface
// but OtherType will since it embeds it
}
type MyType struct{}
func (this *MyType) Foo() string {
return "MyType Foo()"
}
type OtherType struct {
Fooer
}
func (this *OtherType) Foo() string {
return "OtherType Foo()"
}
func PrintFooer(f Fooer) {
fmt.Println(f.Foo())
}
func main() {
mt1 := MyType{}
PrintFooer(&mt1)
// with Bar() exposed in Fooer the above call will fail to compile
// comment the above two lines to fix compile errors
ot1 := OtherType{}
PrintFooer(&ot1)
// with Bar() exposed in Fooer the above call will still work
// ot1.Bar() // uncomment
// since OtherType.Bar() is not implemented
// any call to OtherType.Bar() will cuase a run time error
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment