Coming to the end of one long Udemy tutorial, I knew I needed to write something about this weird language. Something that encapsulates my knowledge but what? I decided to write about my experience with using this new language and trying to build backend applications with it.
This might not provide any mind-blowing insights into Golang as a whole, but if you have a few minutes to kill before going to bed, this might do the trick.
Variables
This might not be a list of programming languages that are diverse in their theology or styles, but I have written applications in C#, Java, Kotlin, and Dart (yes, I'm a mobile developer) and they are all written a certain way. Go is written in a very different kind of way, you get to know that from the jump when you have to declare variables.
The syntax for declaring a new variable, using this `:=` operator takes some getting used to. Collecting the output of a function that returns two or more variables, yes functions casually return two or more variables here, is quite a departure from my normal way of doing things. An example will be written below:
//Simple variable with one value
simpleVariable := "simple variable"
//Collecting outputs from a function that returns two or more outputs
user, err := db.GetUser()
It could even get even fancier if you have to use an inline if statement as shown below:
if err, ok := rawJson.(*PayloadStruct); !ok {
//do something if this operation goes wrong
}
Structs and Interfaces
As you know by now, I come from a very object-oriented background and this means classes. Lots and lots of classes. Well, they are nowhere to be found in Golang. Instead, we have structs. Struct also performs the same functions as classes i.e they group similar data and operations. Interfaces are the same as we all know, with a caveat on their syntax. Take a peek at the description below:
//A struct defining an animal
type Student struct {
Name string
Class string
}
//An interface describing the basic function on an human
type Human interface {
Eat() //Abstract methods are written without the `func` keyword
}
One thing I like about Structs in Golang is the way the methods are defined. Methods/Operations are defined on a Struct by defining a normal function but passing in a pointer to the struct. This means that multiple operations for a struct can be defined in separate files allowing for some pretty neat organization. I will illustrate below:
//An operation on the Student struct we defined above
func (student *Student) takeRoleCall() {
//the student pointer here, contains all the necessary data like
//Name and Class and ven other operations defined on Student
//struct
log.Printf("My name is %s and my class is %s!", student.Name,
student.Class)
}
Another thing, I love is the way interfaces are implemented. According to our example above, we have our Student
struct(class) and our Human
interface. To be able to use our Student
as a Human
, our Student
has to, obviously, implement the Human
interfaces. In other OOP languages, our classes will do this with a specific syntax. This syntax may look something like this:
class Student implements Human {
@override
void Eat() {
System.out.println("I dey eat");
}
}
With Go, it's much simpler. We just have to define a function with the same signature on whatever struct we want, that's all! The signature must correlate with the one defined in the function.
//Student is officially a human
func (student *Student) Eat() {
log.Println("I dey eat!")
}
I find the syntax of doing all these very freeing and a nice departure from a lifetime of stringent ways of doing things.
Inheritance
You might probably be wondering: "If another Struct (class) wants to inherit a whole set of functions from another Struct (class), how would that work?", "What is Go's version of extends
". Well, it's time to talk about composition and struct embedding.
Let's say it turns out our Student
is actually a part-time Lecturer
. Let's look at our definition of a Lecturer
type Lecturer struct {
Course string
}
//The main teach method on the Lecturer struct
func (lecturer *Lecturer) Teach() {
log.Printf("Hi everyone, I teach %s", lecturer.Course)
}
The Student
has to be able to teach and so he has to inherit the Lecturer
's Teach function. Struct does this by composition. Composition is arguably a better method of achieving polymorphism by allowing your classes/structs to contain instances of other classes/structs that provide the needed functionality. You can read more about Composition and how it differs from classical Inheritance here.
Golang makes this easy to write by giving us Struct embedding. It looks something like this:
//We'll be making our Student inherit the Lecturer's Teach
//operation
type Student struct {
//This is struct embedding
Lecturer
Name string
Class string
}
func main(){
//After initializing a `student` instance like this
student := Student {
Name: "Favour Olukayode",
Class: "Classy"
Lecturer: {
Course: "CSC"
}
}
//We can directly call the `Teach` function on the `student`
student.Teach() //Hi everyone, I teach Classy
}
This was something that took some getting used to but was also a new way to look at things.
Slices
Slices, oh Slices. I don't like slices. The very concept and syntax aren't something I'm very comfortable with. Slices are Golang's way of declaring a List. Basically a way of declaring an array without a predefined number of items of the same data type. This is the one area where I prefer my old OOP life. But, for the sake of the article, let's take a look at the syntax.
//The syntax looks like this nuSlice := []datatype{values}
//We'll be declaring an no values like this
myFirstSlice := []string{}
//Declaring a slice with values look this
sliceWithPredefinedValue := []int{1, 2, 3, 4, 6, 7}
//Slices can also be created with the make function, felt it was
//worth mentioning too.
//The syntax: makeSlice := make([]type, length, capacity)
makeSlice := make([]int, 10)
//Defining the make slice without the capacity makes the capacity equal to the length
//Grabbing an element via its position should be something you're
//familiar with
value := makeSlice[5]
//The element at index, 5.
But wait, there's more! Other OOPLs have a standard library for making modifications to lists and arrays, and Golang has built-in functions that are similar to what they achieve. They are written in a different way though. I will make a distinction below:
//To get the length of a list, in kotlin
//list.length
//With Go,
length := len(makeSlice)
log.Print(length) //10
//To add an element to a list, in kotlin
//list.add(10)
//With Go,
append(sliceWithPredefinedValue, 11)
//This will add an element to the end of the slice. This also provides a nifty ability to append one slice to another, providing a new combined slice
newSlice := append(sliceWithPredefinedValue, makeSlice)
There is a LOT more stuff that can be done with a slice, You can read more here. Slices are one of Golang's many ways of being memory efficient, it has a lot of underlying implementations that are worth reading about.
That's a warp!
This is everything I found new and shiny with Golang. There is a lot more stuff but I found these worth mentioning. I'm looking forward to building scalable applications with Go and hopefully becoming a master.