What is the Go Programming Language

grayscale photo of computer laptop near white notebook and ceramic mug on table
Reading Time: 4 minutes

Intro to GO

The Go language was designed with simplicity in mind and therefore the language has few keywords, constructs and built-ins. But what is included is carefully put together and mixes well with the other language constructs. As a comparison, Go has 25 keywords whereas ANSI C has 32, Java has 50 and C++11 has 84. The language specification for Go is said to “be simple enough so that every programmer can have it in their heads”, but, it still has some very important concepts that every programmer must know. In this blog I am going to mainly focus on the basics of Go which makes it unique from other programming languages.

Syntax of Go:

The syntax will be familiar for programmers used to languages from the C-syntax family but it is clean and resembles how easy it is to write Python code.

package main
import (
func main(){
   fmt.Println("Hello, World!")

First the package is specified, in this case the main package since this package will contain a main function. After that we have a list of imported packages, in this case the standard string formatting package. Then we see a declaration of the main function comes, with no arguments and no return value. As can be seen, statements in Go are not semicolon terminated. The type visibility is determined by the first letter of the name like the Println() function from the fmt package. Type names beginning with a capital letter are exported whereas lower cased names are not visible outside the defining scope.

Types in Go:

Go has the types: integers, floating point numbers, strings, characters (UTF-8, named runes and can be of variable size). 

var i int // All Go types have sensible zero values , 0 here 
j := 3.14  // Type is inferred , float64 on our machine 
str0 := " gopher "
var str1 *string = & str0   // str is a pointer to a string

Another rather unusual feature of the language is that it supports multiple and named return values. Multiple return values are typically used for returning an error since exceptions are excluded from the language.

func distance ( p1 , p2 uint ) ( dist uint , err error ) {
   dist = 0 
   err = nil 
   if p1 > p2 { 
   err = errors . New ("the second point must be the farthest away from origin ") 
    dist = p2-p1
func main() {
     var d unit
     var err error
     if d, err = distance(2,7);err!=nil{
           log . Fatalf (" Invalid computation : %s", err ) 
     log . Printf ("%d\n", d ) 

Slices in Go:

Apart from simple arrays of compile-time known sizes there are dynamic arrays named slices.

package main
func main(){
    var colors = []string{"Red","Green","Blue"}
    // Adding values
    colors = append(colors, "Purple")
    //Removing first element
    colors = append(colors[1:len(colors)])
    //Declaring slice with built-in make function
    numbers := make([]int,4,5)
    numbers[0] = 1
    numbers[1] = 3
    numbers[2] = 4
    numbers[3] = 7
    //Appending into numbers
    numbers = append(numbers, 235)
    numbers = append(numbers, 125)
    numbers = append(numbers, 54)
    /*Printing capacity of numbers. The capacity increases to a much higher number than what we would expect because it gives up extra memory to reduce operational workload.*/
    //Sorting a slice


[Red Green Blue]
[Red Green Blue Purple]
[Green Blue Purple]
[Green Blue]
[1 3 4 7]
[1 3 4 7 235 125 54]
[1 3 4 7 54 125 235]


An object is often described as a structure that represents a concept, manages some information and provides means for operating on them. Therefore, Go has structs which provides ways for operating on that structure which makes it Object Oriented. Methods on a struct can be specified by annotating a normal function declaration with what is called a method receiver in Go. A method receiver makes the specified type instance (can be of any type) available in the scope of the function and it also enables call on the struct’s method with the classic dot notation.

type Object struct {
     name string
func ( o Object ) GetName () string {
      return o . name
func ( o * Object ) SetName ( name string ) {
      o.name = name
func ( o Object ) String () string { 
      return fmt . Sprintf (" Object with name %s", o.name )
func main () {
      obj0 := Object {" obj0 "} 
      obj1 := Object { name : obj0 . GetName () } 
      obj0.SetName (" masts ") 
      fmt . Printf ("%s\n", obj1 )

In the main function we see two ways of initializing a struct: with positional or named values. Thus you can notice the difference between how the method receivers are declared in Object.GetName() and Object.SetName(). If the receiver is a type, it is a copy of the object and any changes to its field will not affect the original. To change the value we need a pointer receiver, which also avoids unnecessary copying. Method receivers make Go very extensible as we can define them for any type. 

While the language is good and the tools are splendid for the most part, the state of cross-compilation is worse. Cross-compilation is a tricky problem to start with but the Go build tool could have worked better with gccgo. We found that there are people doing cross-compilation with Go, but they are few compared to the rest, meaning that this subject receives little attention in the community.

As the Go user base grows the interest for these tools will grow, but we think it will take a while since this subject is not prioritised. If Go is to be used for embedded programming today, our recommendation is to wait for the tools to become mature or be prepared to spend time on working around the quirks and fixing the build tools.

Hey, readers! Thank you for sticking up till the end. If you have any questions/feedbacks regarding this blog, I am reachable at vidushi.bansal@knoldus.com. You can find more blogs on AWS here.


Written by 

Vidushi Bansal is a Software Consultant [Devops] at Knoldus Inc. She is passionate about learning and exploring new technologies.