Lets-GO!
Thu Sep 26 2024
Eric Thomas D. Cabigting
In the ever-evolving landscape of programming languages, Go (or Golang) has emerged as a true powerhouse, captivating developers with its simplicity, efficiency, and robust performance. Created by Google engineers Robert Griesemer, Rob Pike, and Ken Thompson, Go was designed to address the challenges of modern software development, and it has quickly gained a dedicated following among programmers across the globe.
What makes Go so awesome? For starters, its clean and concise syntax allows developers to write code that is not only easy to read but also easy to maintain. Gone are the days of wrestling with complex language features; Go embraces simplicity, enabling developers to focus on what truly matters: building high-quality software.
Go's impressive concurrency model is another standout feature. With its goroutines and channels, Go makes it a breeze to write programs that can handle multiple tasks simultaneously, unlocking the full potential of modern multi-core processors. This means that whether you're building a web server, a microservice, or a data pipeline, Go can help you achieve remarkable performance with minimal effort.
Moreover, Go's strong standard library and rich ecosystem of third-party packages provide developers with the tools they need to tackle a wide range of projects. From web development to cloud computing, Go has proven itself to be versatile and powerful, making it a go-to choice for startups and established companies alike.
In this blog, we will explore the many reasons why Go is not just another programming language, but a game-changer in the world of software development. Whether you're a seasoned developer looking to expand your skill set or a newcomer eager to dive into the world of coding, Go offers an exciting journey filled with opportunities for growth and innovation. Join me as we delve into the awesomeness of Go and discover how it can elevate your programming experience to new heights!
Method Receiver/Receiver Functions
You can attached a function to a type using the receiver parenthesis in a function signature.
Let say you have a type Todo like this:
type Todo struct {
Title string
Completed bool
CreatedAt time.Time
CompletedAt *time.Time
}
Then you create a slice like this type Todos []Todo
You can add function to your Todos type by adding another parenthesis after the func keyword before the function name in the function signature, like this:
func (todos *Todos) edit(index int, title string) error {
t := *todos
if err := t.validateIndex(index); err != nil {
return err
}
t[index].Title = title
return nil
}
From the function above the (todos *Todos) at the function signature denotes that this function is now a property/member of type Todos
Good to know: the * in the *Todos in the function receiver means you are modifying the todos that called the function. Without the * you are modifying a copy of the todos sent to the function.
Understanding pointers
* is used to dereference a pointer (access the value at the pointer's address).
As an example:
var x int = 42
var p *int = &x // p is a pointer to x
fmt.Println("Value pointed to by p:", *p) // Output: Value pointed to by p: 42
& is used to get the address of a variable (create a pointer).
As an example:
var x int = 42
fmt.Println("Address of x:", &x) // Output: Address of x: <some memory address>
GOOD TO KNOW: any declaration of struct, function or variable names in upper case characters makes them public while lower case makes them private. This means these are accessible from other packages in the same scope.
Key Points to remember
- Pointer Assignment: In the toggle function, when you do:
completionTime := time.Now()
t[index].CompletedAt = &completionTime
You are creating a variable completionTime that holds the current time. You then take the address of this variable using &completionTime and assign it to t[index].CompletedAt, which is a pointer to a time.Time.
- Dereferencing in Print: In your print function, you check if t.CompletedAt is not nil:
if t.CompletedAt != nil {
completedAt = t.CompletedAt.Format(time.RFC1123)
}
Here, t.CompletedAt is a pointer to a time.Time. When you call t.CompletedAt.Format(time.RFC1123), Go automatically dereferences the pointer for you to access the underlying time.Time value. This is why you see the correct formatted date and time instead of a memory address.
Working with Generics in Go
Take the snippet below as an example:
type Storage[T any] struct {
FileName string
}
- Generics: The Storage type is defined as a generic type with a type parameter T. The any constraint means that T can be any type ie. JSON, Todos.
- Field: The Storage struct has a single field, FileName, which is a string that presumably represents the name of the file where data will be stored.
The constructor function:
func NewStorage[T any](fileName string) *Storage[T] {
return &Storage[T]{FileName: fileName}
}
- Constructor: The NewStorage function is a constructor for creating a new instance of Storage. It takes a fileName as a parameter and returns a pointer to a Storage[T] instance.
- Type Parameter: The type parameter T is again specified, allowing the caller to define what type of data will be stored in this instance of Storage.
Using the Generics on a Save function:
func (s *Storage[T]) Save(data T) error {
// Using MarshalIndent saves the data into json format with 4 spaces
fileData, err := json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
// Write the File
// 0644 - owner can read write to the file, user group members can read, everyone else can read
return os.WriteFile(s.FileName, fileData, 0644)
}
- Method Receiver: The Save method is defined on a pointer receiver of type *Storage[T], meaning it can modify the Storage instance it is called on.
- Parameter: The method takes a parameter data of type T, which is the data to be saved.
- JSON Marshalling: The method uses json.MarshalIndent to convert the data into a JSON format with indentation for readability. If there is an error during this process, it returns the error.
File Writing: The method then writes the JSON data to the file specified by FileName using os.WriteFile. The permission mode 0644 means:
- The owner can read and write to the file.
- Group members can read the file.
- Others can also read the file.
Let's Connect
Hey! My inbox is always free! Currently looking for new opportunities. Email me even just to say Hi! or if you have questions! I will get back to you as soon as possible!