Book Image

Go Design Patterns

By : Mario Castro Contreras
Book Image

Go Design Patterns

By: Mario Castro Contreras

Overview of this book

Go is a multi-paradigm programming language that has built-in facilities to create concurrent applications. Design patterns allow developers to efficiently address common problems faced during developing applications. Go Design Patterns will provide readers with a reference point to software design patterns and CSP concurrency design patterns to help them build applications in a more idiomatic, robust, and convenient way in Go. The book starts with a brief introduction to Go programming essentials and quickly moves on to explain the idea behind the creation of design patterns and how they appeared in the 90’s as a common "language" between developers to solve common tasks in object-oriented programming languages. You will then learn how to apply the 23 Gang of Four (GoF) design patterns in Go and also learn about CSP concurrency patterns, the "killer feature" in Go that has helped Google develop software to maintain thousands of servers. With all of this the book will enable you to understand and apply design patterns in an idiomatic way that will produce concise, readable, and maintainable software.
Table of Contents (17 chapters)
Go Design Patterns
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Pointers and structures


Pointers are the number one source of a headache of every C or C++ programmer. But they are one of the main tools to achieve high-performance code in non-garbage-collected languages. Fortunately for us, Go's pointers have achieved the best of both worlds by providing high-performance pointers with garbage-collector capabilities and easiness.

On the other side for its detractors, Go lacks inheritance in favor of composition. Instead of talking about the objects that are in Go, your objects have other . So, instead of having a car structure that inherits the class vehicle (a car is a vehicle), you could have a vehicle structure that contains a car structure within.

What is a pointer? Why are they good?

Pointers are hated, loved, and very useful at the same time. To understand what a pointer is can be difficult so let's try with a real world explanation. As we mentioned earlier in this chapter, a pointer is a like a mailbox. Imagine a bunch of mailboxes in a building; all of them have the same size and shape but each refers to a different house within the building. Just because all mailboxes are the same size does not mean that each house will have the same size. We could even have a couple of houses joined, a house that was there but now has a license of commerce, or a house that is completely empty. So the pointers are the mailboxes, all of them of the same size and that refer to a house. The building is our memory and the houses are the types our pointers refer to and the memory they allocate. If you want to receive something in your house, it's far easier to simply send the address of your house (to send the pointer) instead of sending the entire house so that your package is deposited inside. But they have some drawbacks as if you send your address and your house (variable it refers to) disappears after sending, or its type owner change--you'll be in trouble.

How is this useful? Imagine that somehow you have 4 GB of data in a variable and you need to pass it to a different function. Without a pointer, the entire variable is cloned to the scope of the function that is going to use it. So, you'll have 8 GB of memory occupied by using this variable twice that, hopefully, the second function isn't going to use in a different function again to raise this number even more.

You could use a pointer to pass a very small reference to this chunk to the first function so that just the small reference is cloned and you can keep your memory usage low.

While this isn't the most academic nor exact explanation, it gives a good view of what a pointer is without explaining what a stack or a heap is or how they work in x86 architectures.

Pointers in Go are very limited compared with C or C++ pointers. You can't use pointer arithmetic nor can you create a pointer to reference an exact position in the stack.

Pointers in Go can be declared like this:

number := 5 

Here number := 5 code represents our 4 GB variable and pointer_to_number contains the reference (represented by an ampersand) to this variable. It's the direction to the variable (the one that you put in the mailbox of this house/type/variable). Let's print the variable pointer_to_number , which is a simple variable:

println(pointer_to_number) 
0x005651FA 

What's that number? Well, the direction to our variable in memory. And how can I print the actual value of the house? Well, with an asterisk (*) we tell the compiler to take the value that the pointer is referencing, which is our 4 GB variable.

 println(*pointer_to_number) 
5 

Structs

A struct is an object in Go. It has some similarities with classes in OOP as they have fields. Structs can implement interfaces and declare methods. But, for example, in Go, there's not inheritance. Lack of inheritance looks limiting but in fact, composition over inheritance was a requirement of the language.

To declare a structure, you have to prefix its name with the keyword type and suffix with the keyword struct and then you declare any field or method between brackets, for example:

type Person struct { 
    Name string 
    Surname string 
    Hobbies []string 
    id string 
} 

In this piece of code, we have declared a Person structure with three public fields (Name, Age , and Hobbies) and one private field (id, if you recall the Visibility section in this chapter, lowercase fields in Go refers to private fields are just visible within the same package). With this struct, we can now create as many instances of Person as we want. Now we will write a function called GetFullName that will give the composition of the name and the surname of the struct it belongs to:

func (person *Person) GetFullName() string { 
    return fmt.Sprintf("%s %s", person.Name, person.Surname) 
} 
 
func main() { 
    p := Person{ 
        Name: "Mario", 
        Surname: "Castro", 
        Hobbies: []string{"cycling", "electronics", "planes"}, 
        id: "sa3-223-asd", 
    } 
 
    fmt.Printf("%s likes %s, %s and %s\n", p.GetFullName(), p.Hobbies[0], p.Hobbies[1], p.Hobbies[2]) 
} 

Methods are defined similarly to functions but in a slightly different way. There is a(p *Person) that refers to a pointer to the created instance of the struct (recall the Pointers section in this chapter). It's like using the keyword this in Java or self in Python when referring to the pointing object.

Maybe you are thinking why does (p *Person) have the pointer operator to reflect that p is actually a pointer and not a value? This is because you can also pass Person by value by removing the pointer signature, in which case a copy of the value of Person is passed to the function. This has some implications, for example, any change that you make in p if you pass it by value won't be reflected in source p. But what about our GetFullName() method?

func (person Person) GetFullName() string { 
    return fmt.Sprintf("%s %s", person.Name, person.Surname) 
} 

Its console output has no effect in appearance but a full copy was passed before evaluating the function. But if we modify person here, the source p won't be affected and the new person value will be available only on the scope of this function.

On the main function, we create an instance of our structure called p. As you can see, we have used implicit notation to create the variable (the := symbol). To set the fields, you have to refer to the name of the field, colon, the value, and the comma (don't forget the comma at the end!). To access the fields of the instantiated structure, we just refer to them by their name like p.Name or p.Surname. You use the same syntax to access the methods of the structure like p.GetFullName().

The output of this program is:

$ go run main.go 
Mario Castro likes cycling, electronics and planes

Structures can also contain another structure (composition) and implement interface methods apart from their own but, what's an interface method?