$Id: 281

$SOId: 8801

@draft

Go is not an object oriented programming language. If you're familiar with other OO languages (Python, C++, Java etc.) you'll notice some similarities but you should also understand differences.

Methods encapsulate logic

Structs are similar to classes in that you can define methods on them to encapsulate logic related to a type:

type Person struct {
	firstName string
	lastName string
}

func (p *Person) FullName() string {
	if p.firstName != "" && p.lastName != "" {
		return p.firstName + " " + p.lastName
	}
	return p.firstName + p.lastName
}

u := &Person{firstName: "Jon", lastName: "Snow"}
fmt.Printf("Full name: %s\\n", u.FullName())

We defined FullName() method on type *Person.

Variable p that is a target of the method is called a receiver.

Idiomatic Go style is to use a short name for the receiver based on type name.

A bad Go style is to call the receiver this.

Unlike most languages, you can also implement methods on all types, not just structs.

type myInt int

func (i myInt) String() string {
  return strconv.Atoi(int(i))
}

myInt := 5
fmt.Printf("myInt: %s\\n", myInt.String())

You can only implement methods on your own types (i.e. method must be defined in the same package as the type). That's why we had to introduce myInt alias for int type.

Embedding

type BritishPerson struct {
	Person
  isKnight bool
}

type (p *BritishPerson) IsKnight() bool {
	return p.isKnight
}

p := &BritishPerson{Person: {firstName:"Tim", lastName: "Berners-Lee"}, isKnight: true}
if p.IsKnight() {
	fmt.Printf("%s is a knight\\n", p.FullName())
}

BritishPerson embeds Person anonymously and therefore you can call all Person methods on instances of BritishPerson.

Embedding allows to share common functionality among multiple structs.