GOLang: Interfaces

Saurabh Sharma

Interfaces are an interesting concept to learn in GOLANG. There are a tonne of informative articles and here is my contribution to it.

In classical Object Oriented everything is treated in parlance of Object or Class like in Java or C++. In Go there is no class or inheritance.

Learn by doing

I started of by defining an interface

type MyInterface interface {
	Set(int)
	Get() int
}

Which exposes two methods Get and Set and any user defined object that implements it (as shown below) can be assigned.

What it represents?

Let’s try and print the value and type for a var of type MyInterface

%#v	a Go-syntax representation of the value
%T	a Go-syntax representation of the type of the value
var myIntf MyInterface
fmt.Printf(" Before assigning the object %T %#v\n", myIntf, myIntf)

The output might surprise you – for those coming from the Java background.

Before assigning the object <nil> <nil>

The var myIntf is essentially a pointer with a value of nil.

  • There is no explicit implements like verb in go
  • The interface can be implemented by any number of types
  • Multiple interfaces can be implemented by the same type

Full Program

package main

import "fmt"

// MyInterface defines simple set and get
type MyInterface interface {
	Set(int)
	Get() int
}

// Simple Struct that has only a single Value
type Simple struct {
	u int
}

// Set the value for Simple struct
func (p *Simple) Set(u int) {
	p.u = u
}

//Get returns the value in struct
func (p Simple) Get() int {
	return p.u
}

func main() {
	simple := &Simple{u: 20}
	simple2 := Simple{u: 21}

	fmt.Printf(" Value: %T %#v\n", simple, simple)
	fmt.Printf(" Value: %d\n", simple.Get())

	var myIntf MyInterface
	fmt.Printf(" Before assigning the object %T %#v\n", myIntf, myIntf)

	myIntf = simple
	myIntf.Set(22)
	fmt.Printf(" Value: %T %#v\n", myIntf, myIntf)
	fmt.Printf(" Value: %d\n", myIntf.Get())

	myIntf = &simple2
	myIntf.Set(24)
	fmt.Printf(" Value: %T %#v\n", myIntf, myIntf)
	fmt.Printf(" Value: %d\n", myIntf.Get())
}

Output

API server listening at: 127.0.0.1:19141
 Value: *main.Simple &main.Simple{u:20}
 Value: 20
 Before assigning the object <nil> <nil>
 Value: *main.Simple &main.Simple{u:22}
 Value: 22
 Value: *main.Simple &main.Simple{u:24}
 Value: 24

Multiple Interfaces

How about adding another interface

//Print can do anything
type Print interface {
	Print()
}
//Print Wildcard print
func (p *Simple) Print() {
	fmt.Printf("Type: %T\nValue: %+v\n", p, p)
}

I modified the main code like below to invoke print.

func main() {
	simple := &Simple{u: 20}
	simple2 := Simple{u: 21}

	fmt.Printf(" Value: %T %#v\n", simple, simple)
	fmt.Printf(" Value: %d\n", simple.Get())
	simple.Print()

	var myIntf MyInterface
	fmt.Printf(" Before assigning the object %T %#v\n", myIntf, myIntf)

	myIntf = simple
	myIntf.Set(22)
	fmt.Printf(" Value: %T %#v\n", myIntf, myIntf)
	fmt.Printf(" Value: %d\n", myIntf.Get())
	var print Print
	print = simple
	print.Print()

	myIntf = &simple2
	myIntf.Set(24)
	fmt.Printf(" Value: %T %#v\n", myIntf, myIntf)
	fmt.Printf(" Value: %d\n", myIntf.Get())

	print = &simple2
	print.Print()
}

Output

API server listening at: 127.0.0.1:36898
 Value: *main.Simple &main.Simple{u:20}
 Value: 20
Type: *main.Simple
Value: &{u:20}
 Before assigning the object <nil> <nil>
 Value: *main.Simple &main.Simple{u:22}
 Value: 22
Type: *main.Simple
Value: &{u:22}
 Value: *main.Simple &main.Simple{u:24}
 Value: 24
Type: *main.Simple
Value: &{u:24}

Or, adding another type

//Age struct a siple numberic holder
type Age struct {
	a myInt
}

//Print Wildcard print
func (p *Age) Print() {
	fmt.Printf("Type: %T\nValue: %+v\n", p, p)
}
age := &Age{a: 40}
age.Print()
print = age
print.Print()

Age only implements Print, so in case if we try to use it with the type MyInterface

Value: &{u:24}
Type: *main.Age
Value: &{a:40}
Type: *main.Age
Value: &{a:40}