Reader small image

You're reading from  Go Programming - From Beginner to Professional - Second Edition

Product typeBook
Published inMar 2024
Reading LevelBeginner
PublisherPackt
ISBN-139781803243054
Edition2nd Edition
Languages
Right arrow
Author (1)
Samantha Coyle
Samantha Coyle
author image
Samantha Coyle

Samantha Coyle, a Software Engineer at Diagrid, specializes in Go for cloud-native developer tooling, abstracting application development challenges. Committed to Open Source, she contributes to projects like Dapr and Testcontainers. She boasts a rich history in retail computer vision solutions and successfully stabilized industrial edge use cases with testing and diverse deployments for biopharma data pipelines. Her expertise extends to being CKAD certified and reviewing Go textbooks. She is passionate about empowering early-career, diverse professionals. Samantha is in a family of gophers, and enjoys GopherCon with her brother and identical twin sister. She's a seasoned speaker, having presented at various conferences, including GopherCon.
Read more about Samantha Coyle

Right arrow

Enums

Enums are a way of defining a fixed list of values that are all related. Go doesn’t have a built-in type for enums, but it does provide tools such as iota to let you define your own using constants. We’ll explore this now.

For example, in the following code, we have the days of the week defined as constants. This code is a good candidate for Go’s iota feature:

…
const (
  Sunday  = 0
  Monday  = 1
  Tuesday = 2
  Wednesday = 3
  Thursday = 4
  Friday  = 5
  Saturday = 6
)
…

With iota, Go helps us manage lists just like this. Using iota, the following code is equal to the preceding code:

…
const (
  Sunday = iota
  Monday
  Tuesday
  Wednesday
  Thursday
  Friday
  Saturday
)
…

Now, we have iota assigning the numbers for us. Using iota makes enums easier to create and maintain, especially if you need to add a new value to the middle of the code later. Order matters when using iota as it is an identifier that tells the Go compiler to start the first value at 0 and increment by 1 for each subsequent value in the case of this example. With iota, you can skip values using _, start with a different offset, and even use more complicated calculations.

Next, we’ll take a detailed look at Go’s variable scoping rules and how they affect how you write code.

Scope

All the variables in Go live in a scope. The top-level scope is the package scope. A scope can have child scopes within it. There are a few ways a child scope gets defined; the easiest way to think about this is that when you see {, you are starting a new child scope, and that child scope ends when you get to a matching }. The parent-child relationship is defined when the code compiles, not when the code runs. When accessing a variable, Go looks at the scope the code was defined in. If it can’t find a variable with that name, it looks in the parent scope, then the grandparent scope, all the way until it gets to the package scope. It stops looking once it finds a variable with a matching name or raises an error if it can’t find a match.

To put it another way, when your code uses a variable, Go needs to work out where that variable was defined. It starts its search in the scope of the code using the variable it’s currently running in. If a variable definition using that name is in that scope, then it stops looking and uses the variable definition to complete its work. If it can’t find a variable definition, then it starts walking up the stack of scopes, stopping as soon as it finds a variable with that name. This searching is all done based on a variable name. If a variable with that name is found but is of the wrong type, Go raises an error.

In this example, we have four different scopes, but we define the level variable once. This means that no matter where you use level, the same variable is used:

package main
import "fmt"
var level = "pkg"
func main() {
  fmt.Println("Main start :", level)
  if true {
    fmt.Println("Block start :", level)
    funcA()
  }
}
func funcA() {
  fmt.Println("funcA start :", level)
}

The following is the output displaying variables when using level:

Main start : pkg
Block start : pkg
funcA start : pkg

In this example, we’ve shadowed the level variable. This new level variable is not related to the level variable in the package scope. When we print level in the block, the Go runtime stops looking for variables called level as soon as it finds the one defined in main. This logic results in a different value getting printed out once that new variable shadows the package variable. You can also see that it’s a different variable because it’s a different type, and a variable can’t have its type changed in Go:

package main
import "fmt"
var level = "pkg"
func main() {
  fmt.Println("Main start :", level)
  // Create a shadow variable
  level := 42
  if true {
    fmt.Println("Block start :", level)
    funcA()
  }
  fmt.Println("Main end :", level)
}
func funcA() {
  fmt.Println("funcA start :", level)
}

The following is the output:

Main start : pkg
Block start : 42
funcA start : pkg
Main end : 42

Go’s static scope resolution comes into play when we call funcA. That’s why, when funcA runs, it still sees the package scope’s level variable. The scope resolution doesn’t pay attention to where funcA gets called.

You can’t access variables defined in a child scope:

package main
import "fmt"
func main() {
  {
    level := "Nest 1"
    fmt.Println("Block end :", level)
  }
  // Error: undefined: level
  //fmt.Println("Main end  :", level)
}

The following is the output:

Figure 1.23: Output displaying an error

Figure 1.23: Output displaying an error

Activity 1.03 – message bug

The following code doesn’t work. The person who wrote it can’t fix it, and they’ve asked you to help them. Can you get it to work?

package main
import "fmt"
func main() {
  count := 5
  if count > 5 {
    message := "Greater than 5"
  } else {
    message := "Not greater than 5"
  }
  fmt.Println(message)
}

Follow these steps:

  1. Run the code and see what the output is.
  2. The problem is with message; make a change to the code.
  3. Rerun the code and see what difference it makes.
  4. Repeat this process until you see the expected output.

    The following is the expected output:

    Not greater than 5

In this activity, we saw that where you define your variables has a big impact on the code. Always think about the scope you need your variables to be in when defining them.

In the next activity, we are going to look at a similar problem that is a bit trickier.

Activity 1.04 – bad count bug

Your friend is back, and they have another bug in their code. This code should print true, but it’s printing false. Can you help them fix the bug?

package main
import "fmt"
func main() {
  count := 0
  if count < 5 {
    count := 10
    count++
  }
  fmt.Println(count == 11)
}

Follow these steps:

  1. Run the code and see what the output is.
  2. The problem is with count; make a change to the code.
  3. Rerun the code and see what difference it makes.
  4. Repeat this process until you see the expected output.

The following is the expected output:

True
Previous PageNext Page
You have been reading a chapter from
Go Programming - From Beginner to Professional - Second Edition
Published in: Mar 2024Publisher: PacktISBN-13: 9781803243054
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Samantha Coyle

Samantha Coyle, a Software Engineer at Diagrid, specializes in Go for cloud-native developer tooling, abstracting application development challenges. Committed to Open Source, she contributes to projects like Dapr and Testcontainers. She boasts a rich history in retail computer vision solutions and successfully stabilized industrial edge use cases with testing and diverse deployments for biopharma data pipelines. Her expertise extends to being CKAD certified and reviewing Go textbooks. She is passionate about empowering early-career, diverse professionals. Samantha is in a family of gophers, and enjoys GopherCon with her brother and identical twin sister. She's a seasoned speaker, having presented at various conferences, including GopherCon.
Read more about Samantha Coyle