go enum

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 19

Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.

com/chap-27-enum-iota-and-bitmask

Chapter 27: Enum, Iota & Bitmask

1 What will you learn in this chapter?


• What is an enum?

• How to create an enum with Go.

• What is iota, and how to use it?

• What are bitwise operators, and how to use them?

2 Technical concepts covered


• Enum

• Enumeration type

• iota

• index

• Byte, bits

• Binary

• Bitmask, Bitflag

3 Enum definition
An “enum” (or enumeration data type) is a data type that consists of a set of “values that are explicitly defined by the programmer”
[@institute1990ieee]

For example, days of the week are an enum. There are seven days of the week and not more.

The paper and the digital edition of this book are available here. ×
I also filmed a video course to build a real world project with Go.

4 Go and enums
The language (at least in its version 1) does not have specific enumeration types. However, we can still build a type that offers the same
features as enums.

5 Building a type that can be used “as” enum.


Let’s take the example of HTTP methods.

1 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

// enum-iota-bitmasks/type-as-enum/main.go

type HTTPMethod int

const (
GET HTTPMethod = 0
POST HTTPMethod = 1
PUT HTTPMethod = 2
DELETE HTTPMethod = 3
PATCH HTTPMethod = 4
HEAD HTTPMethod = 5
OPTIONS HTTPMethod = 6
TRACE HTTPMethod = 7
CONNECT HTTPMethod = 8
)

• First, we declare a new type HTTPMethod (its underlying type is int ).

• Then we create nine constants of type HTTPMethod

• Each constant is of type HTTPMethod and is named like the HTTP method its designates.

5.0.1 Why integers?


You are free to use an underlying type different from int .

However, this is a common practice to use integers.

• It’s generally more efficient to compare an integer with another integer instead of comparing a string with another string

• You can use iota. (see next sections)

5.0.2 Usage Example


Imagine that you have a function that handles HTTP requests.

In this function, you expect the user to give you an HTTP method, and you expect to handle a predefined set of methods. Your function can
have a parameter of type HTTPMethod (instead of int ) :

func handle(method HTTPMethod, headers map[string]string, uri string) {}

Inside the function body, you can adapt the behavior of your handler by using the enum values :

func handle(method HTTPMethod, headers map[string]string, uri string) {


if method == GET {
fmt.Println("the method is get")
} else {
fmt.Println("the method is not get")
}
}

Enums types can also be used in structs (like any other types) :

// enum-iota-bitmasks/type-as-enum/main.go

type HTTPRequest struct {


method HTTPMethod
headers map[string]string
uri string
}
func main() {
r := HTTPRequest{method: GET, headers: map[string]string{"Accept": "application/json"}, uri: "/prices"}
fmt.Println(r)
}

6 A perfectible solution
The solution proposed in the previous section is not perfect. Here is why :

• Any int can be a variable of type HTTPMethod :

2 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

lolMethod := HTTPMethod(42)
headers := make(map[string]string)
handle(lolMethod,headers,"/prices" )

We created a variable lolMethod which is of type HTTPMethod and the code will compile.

• When we print an HTTPMethod the output is an int :

log.Println(GET)
// > 0

• When marshaled to JSON, a value of type HTTPMethod will be printed as an int ...

type HTTPRequest struct {


Method HTTPMethod `json:"method"`
Headers map[string]string `json:"headers"`
Uri string `json:"uri"`
}
r := HTTPRequest{Method: GET, Headers: map[string]string{"Accept": "application/json"}, Uri: "/prices"}
marshaled, err := json.Marshal(r)
if err != nil {
panic(err)
}

Will produce the following JSON string:

{
"method": 0,
"headers": {
"Accept": "application/json"
},
"uri": "/prices"
}

The value 0 might be interpreted as an error. Instead, we want to output "GET" .

• When we want to unmarshal a JSON string, we might encounter an error :

jsonB := []byte("{\"method\":\"GET\",\"headers\":{\"Accept\":\"application/json\"},\"uri\":\"/prices\"}")
req := HTTPRequest{}
err = json.Unmarshal(jsonB,&req)
if err != nil {
panic(err)
}

We got a panic :

panic: json: cannot unmarshal string into Go struct field HTTPRequest.method of type main.HTTPMethod

This is perfectly normal, we have a string as input, and we want to convert it to an int. One solution could be to change the underlying type to
string.

7 Enum libraries
To solve the previous issues :

• We need to be able to check if a value is part of the enum

◦ We need a method that validates a value


• We need to be able to print an element correctly

◦ We need to implement the fmt.Stringer interface


• We need to be able to marshal correctly an enum value into JSON (an maybe into another format)

◦ We need to implement the json.Marshaler interface


• We need to be able to unmarshal correctly an enum value from JSON (an maybe from another format)

◦ We need to implement the json.Unmarshaler interface

3 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

We can implement those interfaces :

// enum-iota-bitmasks/enum-implementations/main.go

type HTTPMethod int

func (h HTTPMethod) IsValid() bool {


panic("implement me")
}

func (h HTTPMethod) String() string {


panic("implement me")
}

func (h HTTPMethod) UnmarshalJSON(bytes []byte) error {


panic("implement me")
}

func (h HTTPMethod) MarshalJSON() ([]byte, error) {


panic("implement me")
}

However, this is tedious. We can use a library to do that for us. After a quick search on GitHub, it seems that two libraries emerge :

• https://github.com/alvaroloes/enumer

• https://github.com/abice/go-enum

They will generate those methods for you. They offer a command-line interface.

Note that the support for enums is a feature request for version 2 of the language.

The paper and the digital edition of this book are available here. ×
I also filmed a video course to build a real world project with Go.

8 Iota
In the previous section:

• We needed to assign an integer to each constant.

• The type HTTPMethod is also written on each line.

To avoid those two tasks, we can modify our enum to use iota :

// enum-iota-bitmasks/iota/main.go
package main

import "fmt"

type HTTPMethod int

const (
GET HTTPMethod = iota
POST HTTPMethod = iota
PUT HTTPMethod = iota
DELETE HTTPMethod = iota
PATCH HTTPMethod = iota
HEAD HTTPMethod = iota
OPTIONS HTTPMethod = iota
TRACE HTTPMethod = iota
CONNECT HTTPMethod = iota
)

func main() {
fmt.Println(PUT)
// 2
}

We can simplify this code. It’s possible to avoid repeating HTTPMethod = iota each time by using the implicit repetition property. This

4 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

property is very handy; it says that inside a constant set ( const(...) ) you can assign a value just to the first const:

// enum-iota-bitmasks/iota-improvement/main.go

const (
GET HTTPMethod = iota
POST
PUT
DELETE
PATCH
HEAD
OPTIONS
TRACE
CONNECT
)

8.0.1 How does iota work


• “iota represents successive untyped integer constants”[@go-specs]

• It means that iota is always an integer; it’s impossible to use iota to construct floats values (for instance).

• “Its value is the index of the respective ConstSpec in that constant declaration”[@go-specs]

The value of iota is determined by the index of the constant in the constant declaration. In the previous example, POST is the second constant
then it has a value of 1. Why 1? Why not 2? That’s because of the third property of iota :

• it starts at zero [@go-specs]

The initial value of iota is zero. Example :

type TestEnum int

const (
First TestEnum = iota
Second
)

fmt.Println(First)
// 0

iota is initialized with zero. If you want that your first enum element starts with something other than zero, you can assign a different value to
the initial constant :

type TestEnum int

const (
First TestEnum = iota +4
Second
)

fmt.Println(First)
// 4 (0+4)

You can also multiply iota by an integer :

type TestEnum int

const (
First TestEnum = iota * 3
Second
)

fmt.Println(Second)
// 3 (1*3)

5 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

iota value

9 Byte / Bit
A byte is composed of 8 bits of memory. A bit is a binary digit. It’s either equal to 0 or 1.

Bit and bytes[fig:Bit-and-bytes]

The indexing of bits is not natural; we start counting from right to left (and not left to right).

10 Operations on bits
The first step before jumping to bitwise operators is to learn how to print the binary representation of a number.

10.1 Print the bits


To print the bits of a number, you can use the fmt.Printf() function with the format specifier %08b.08 means that we will print the binary value
on 8 bits.

// enum-iota-bitmasks/print-bits/main.go
package main

import "fmt"

func main() {
var x uint8
x = 1
fmt.Printf("%08b\n", x)
//00000001
x = 2
fmt.Printf("%08b\n", x)
//00000010
x = 255
fmt.Printf("%08b\n", x)
//11111111
}

6 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

In the previous code listing, we define X, an unsigned integer stored on 8 bits. X can take the values from 0 to 255. We assign to x the value 1,
then 2, and 255. Each time we are printing the binary representation.

10.2 Bitwise operations


To do operations on bits, we need operators. We call those operators “bitwise operators” In this section, we will go through all of them.
Operations on bits can be intimidating initially, but they are nothing else than boolean logic. If you are already familiar with AND, OR, XOR,
etc... it will be easy to understand.

An operation can be decomposed into three elements :

• The operator

• The operands

• The result

For instance, in the operations x | y = z x and y are operands

| is the operator

z is the result For each operator, the same logic applies. Operations are performed independently on each bit of the operands.

Bitwise operators do not have to be mixed up with logical operators (&&, || and !). Those operators are used to compare boolean values from
left to right.

• Warning: you can use the following operators with integers only.

10.2.1 AND operator : &


• If x and y are two bits

x & y is equal to 1 only if x and y are equal to 1.

• Otherwise x & y is equal to 0. J

• ust remember that it’s only true if both operands are true.

x y x&y
00 0
01 0
11 1
10 0

AND
bitwise
operator

Let’s take an example :

// enum-iota-bitmasks/bitwise-operations/main.go

var x, y, z uint8
x = 1 // 00000001
y = 2 // 00000010
z = x & y

// print in binary
fmt.Printf("%08b\n", z)
// 00000000

// print in base 10
fmt.Printf("%d\n", z)
// 0

3 integers variables are created ( x , y , z ). Then we store x & y in the variable z .

7 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

AND bitwise operation example[fig:AND-bitwise-operation]

As shown in figure 2 we take each bit individually, and then we are calculating the result of every; that’s single operation : 1 & 0 = 0

0 & 1 = 0

0 & 0 = 0

0 & 0 = 0

0 & 0 = 0

0 & 0 = 0

0 & 0 = 0

0 & 0 = 0 Note that we begin by the right side. Get used to it; that’s the rule when you manipulate bits.

Let’s take another example :

// enum-iota-bitmasks/bitwise-operation-and/main.go

var x, y, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

y = 100 // 01100100
fmt.Printf("%08b\n", y)

z = x & y

// print in binary
fmt.Printf("%08b\n", z)
// 01000000

// print in base 10
fmt.Printf("%d\n", z)
// 64

In the figure 3 you can see the detail of the operation 200&100.

8 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

AND bitwise operation example[fig:AND-ex-2]

10.2.2 OR operator : |
x | y is equal to 1 if :

• one of the operands is equal to 1

• both operands are equal to 1.

x y x|y
00 0
01 1
11 1
10 1

OR
bitwise
operator

Here is an example in go :

// enum-iota-bitmasks/bitwise-or/main.go

var x, y, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

y = 100 // 01100100
fmt.Printf("%08b\n", y)

z = x | y

// print in binary
fmt.Printf("%08b\n", z)
// 11101100

// print in base 10
fmt.Printf("%d\n", z)
// 236

9 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

OR bitwise operation example[fig:OR-ex]

In the figure 4 you can see that we apply the or operation bit by bit. Starting from the right : 0 | 0 = 0

0 | 0 = 0

0 | 1 = 1

1 | 0 = 1

0 | 0 = 0

0 | 1 = 1

1 | 1 = 1

0 | 1 = 1 When we use the base ten notation for the operands and the result, it does not make sense. Let’s use the binary notation :

11001000 | 01100100 = 11101100

With OR, we set to 1 the bits of the left operand that are set to 1 in the right operand. (you can switch left and right, and this will also work).

10.2.3 XOR operator : ^


The XOR abbreviation stands for e Xclusive OR. Why do we need to add another or? Is the one that we defined before not sufficient?
Remember that with OR we have the following result 1 | 1 = 1 .

When both operands are true, the result is true. Sometimes this behavior isn’t acceptable. We want maybe to exclude that case.

With the exclusive or : 1 ^ 1 = 0 . To be more precise, we have the following rule that applies: x ^ y is equal to 1 only if one of the
operands is equal to 1, not both.

10 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

// enum-iota-bitmasks/bitwise-xor/main.go

var x, y, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

y = 100 // 01100100
fmt.Printf("%08b\n", y)

z = x ^ y

// print in binary
fmt.Printf("%08b\n", z)
// 10101100

// print in base 10
fmt.Printf("%d\n", z)
// 172

The XOR set to 0 the bits that are identical in the two operands and set to 1 the bits that are different.

10.2.4 NOT Operator : ^


The NOT operator is the same as the XOR operator except that we use it in front of only one operand. It’s pretty easy to remember because
this operator will reverse the values that will be stored by each bit :

• ^0 = 1

• ^1 = 0

NOT will invert the values of the bits. Let’s take an example :

// enum-iota-bitmasks/bitwise-not/main.go

var x, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

z = ^x

// print in binary
fmt.Printf("%08b\n", z)
// 00110111

// print in base 10
fmt.Printf("%d\n", z)
// 55

NOT bitwise operation example[fig:NOT-bitwise-operation]

10.2.5 AND NOT operator : &^ (bit clear)


The AND NOT operator is used to set to zero the bits of the left operand if the corresponding bit in the right operand is set to 1. This might
be obscure, so I suggest you to take a look at the figure 6.

11 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

AND NOT bitwise operation example[fig:AND-NOT]

This operator mixes the operator AND and NOT. We can decompose it :

• x AND NOT y is equivalent to :

• x AND (NOT y)

Let’s try to obtain the same result as before with this decomposition :

Let’s denote :

• x = 11001000

• y = 11111111

• NOT y = 00000000

• x AND NOT y is equivalent to

• 11001000 AND 00000000 = 00000000

10.2.6 Left and right shift ( << , >> )


Those operators are used to move the bits to the left or to the right.

You have to specify the number of positions by which the bits will be shifted.

10.2.6.1 Left shift


// enum-iota-bitmasks/bitwise-left-shift/main.go

var x, n, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

// number of positions
n = 1
z = x << n
// print in binary
fmt.Printf("%08b\n", z)
// 10010000

// print in base 10
fmt.Printf("%d\n", z)
// 144

In the previous example, we are left-shifting the byte 11001000 by one position. The result of this shift is 10010000. We have added a zero at
the left of the byte and shifted the other by 1 position as you can see in the figure 7.

12 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

LEFT SHIFT bitwise operation example[fig:LEFT-SHIFT-bitwise]

We are storing our integers into 8 bits, so we are losing bits. to avoid that, we can store our numbers on 16 bits (2 bytes) :

var x, n, z uint16
x = 200 // 11001000
fmt.Printf("%08b\n", x)

// number of positions
n = 1
z = x << n
// print in binary
fmt.Printf("%b\n", z)
// 110010000

// print in base 10
fmt.Printf("%d\n", z)
// 400

You can note something interesting; we have multiplied our number by 2.

200 << 1 = 400

When you left shift the binary representation of a number by n position you multiply it’s decimal representation bt it by two at the power n.

For instance, if you left shift by 3, you will multiply your number by two at the power three, which is 8 :

var x, n, z uint16
x = 200 // 11001000
fmt.Printf("%08b\n", x)

// number of positions
n = 3
z = x << n
// print in binary
fmt.Printf("%b\n", z)
// 11001000000

// print in base 10
fmt.Printf("%d\n", z)
// 1600

10.2.6.2 Right Shift


The operator >> allow you to shifts the bits to the right :

13 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

// enum-iota-bitmasks/bitwise-right-shift/main.go

var x, n, z uint8
x = 200 // 11001000
fmt.Printf("%08b\n", x)

// number of positions
n = 3
z = x >> n
// print in binary
fmt.Printf("%08b\n", z)
// 00011001

// print in base 10
fmt.Printf("%d\n", z)
// 25

You can see here that we are dividing 200 by 3 when we shift the bytes to the right. This is another property of binary numbers. When you
left shift the binary representation of a number (in base 10) by n position, you divide it by two at the power n.

11 Bitmasks (advanced)[sec:Bitmasks]
Imagine that you are building a function that requires eight boolean values to be configured :

1. Is verbose mode activated?

2. Is configuration loaded from disk?

3. Is database connexion required?

4. Is logger activated?

5. Is debug mode activated?

6. Is support for float activated?

7. Is recovery mode activated?

8. Reboot on failure?

What we can do instead is passing just an integer value. This integer value can represent the configuration.

For instance, 01110001 (113 in base 10) will represent the following configuration :

1. Activated (1)

2. Deactivated (0)

3. Deactivated (0)

4. Deactivated (0)

5. Activated (1)

6. Activated (1)

7. Activated (1)

8. Deactivated (0)

Remember that when bytes are involved, we read from right to left.

What are the advantages?

• We improve the code readability; we pass only an argument instead of 8

• We spare memory. If we had eight booleans, we have 8*8 bits = 64 bits used compared to only 8.

We will use the left shift bitwise operation. The idea is the first configuration value is equal to 1 (00000001), and then for each new
configuration variable, we will left shift the bit :

14 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

type MyConf uint8

const (
VERBOSE MyConf = 1 << iota
CONFIG_FROM_DISK
DATABASE_REQUIRED
LOGGER_ACTIVATED
DEBUG
FLOAT_SUPPORT
RECOVERY_MODE
REBOOT_ON_FAILURE
)

The values that are generated by this constant declaration are the following :

• VERBOSE : 00000001

• CONFIG_FROM_DISK : 00000010

• DATABASE_REQUIRED : 00000100

• LOGGER_ACTIVATED : 00001000

• DEBUG : 00010000

• FLOAT_SUPPORT : 00100000

• RECOVERY_MODE : 01000000

• REBOOT_ON_FAILURE : 10000000

We are left shifting the byte for each new constant by an iota. Remember that iota’s value increases when there is a new constant declared.
The code listing above is equivalent to :

// enum-iota-bitmasks/flags/main.go

const (
VERBOSE MyConf = 1 << 0
CONFIG_FROM_DISK MyConf = 1 << 1
DATABASE_REQUIRED MyConf = 1 << 2
LOGGER_ACTIVATED MyConf = 1 << 3
DEBUG MyConf = 1 << 4
FLOAT_SUPPORT MyConf = 1 << 5
RECOVERY_MODE MyConf = 1 << 6
REBOOT_ON_FAILURE MyConf = 1 << 7
)

11.0.0.0.1 Configuration usage


Now it’s time to use our configuration enum. The function that we will use is the following one :

// enum-iota-bitmasks/flags/main.go

func MyComplexFunction(conf MyConf, databaseDsn string) {


//...
}

The configuration is now just a single argument of type MyConf (which is an uint8 behind).

When we call our function, we just have to provide the required flags :

MyComplexFunction(VERBOSE|REBOOT_ON_FAILURE, "mysql...")

Here we tell our function that we want to activate the verbose mode and reboot on failure. The value of VERBOSE|REBOOT_ON_FAILURE is
equal to 10000001. Only two bits are set to 1, the first (VERBOSE) and the last (REBOOT_ON_FAILURE).

11.0.0.0.2 Reading a configuration variable


To check if a flag is set, we can use the AND bitwise operation. For instance, if we want to check if the bit corresponding to
REBOOT_ON_FAILURE is set in confthe following test can be used :

15 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

conf & REBOOT_ON_FAILURE != 0

If the previous expression is true, it means that the flag is set.

Let’s take an example :

// enum-iota-bitmasks/flags/main.go

func main(){
MyComplexFunction(VERBOSE|REBOOT_ON_FAILURE, "test")
}
func MyComplexFunction(conf MyConf, databaseDsn string) {
fmt.Printf("conf : %08b\n", conf)
test := conf & REBOOT_ON_FAILURE
fmt.Printf("test : %08b\n", test)
}

The execution of the previous program will output :

conf : 10000001
test : 10000000

The variable test is different of 0 (00000000 as a byte). It seems to work. Let’s take another example :

test2 := conf & CONFIG_FROM_DISK

is equal to 00000000. The flag is not set.

11.0.0.0.3 Toggle a specific bitflag


The operation to use here is the XOR. For instance, imagine that you have a config variable set, but you wish to activate a deactivated flag (or
deactivate an activated flag) :

// toogle FLOAT_SUPPORT => Activate


conf = conf ^ FLOAT_SUPPORT
test = conf & FLOAT_SUPPORT
fmt.Printf("test : %08b\n", test)

The previous snippet will output :

test 00100000

The flag has been toggled; the test says that it is now activated.

11.0.0.0.4 Clear a specific bitflag


To clear a flag, the bitwise operation to use is AND NOT. Here is an example where FLOAT_SUPPORT has been previously activated :

conf = conf &^ FLOAT_SUPPORT


test = conf & FLOAT_SUPPORT
fmt.Printf("test : %08b\n", test)

Will output 00000000, which means that the flag has been cleared from conf.

11.0.0.1 Summary

16 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

Go is a compiled language

The paper and the digital edition of this book are available here. ×
I also filmed a video course to build a real world project with Go.

12 Test yourself
12.1 Questions
//snippet 1
type Elem uint8

const (
OptB Elem = iota + 5
OptA
OptC
)

1. True or False. Go version 1 supports enum types.

2. What is the value of OptA in snippet 1 (see below)?

3. What are the binary operators for AND, OR, XOR, NOT, AND NOT?

4. What is the type of OptC ?

5. What is the operator to shift to the left a binary digit?

12.2 Answers
1. True or False. Go version 1 supports enum types.

1. False

2. When you want to create an enum type, you will need to write additional methods

2. What is the value of OptA in snippet 1 (see below)?

1. 6 (1+5)
3. What are the binary operators for AND, OR, XOR, NOT, AND NOT?

1. AND : &

2. OR : |

3. XOR : ^

4. NOT : ^

5. AND NOT : & ^

17 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

4. What is the type of OptC ?

1. Elem
5. What is the operator to shift to the left a binary digit ?

1. >>

13 Key takeaways
• An enumeration type (or enum) is a data type that is composed of a set of values explicitly defined

◦ Ex: The days of the week

◦ Ex: The months of the year

◦ Ex: The statuses of an e-commerce order (Created, Locked, Paid, Shipped, ...)

• Go version 1 does not support enumeration types out of the box

• However, you can follow this recipe to create an enum E

◦ Create a new type E .

◦ The underlying type of E is int

◦ Define a set of constants of type E

◦ The first constant has the value 0 , the second 1 , .…

◦ Each constant is an enum element. They need to be named accordingly.

◦ E needs to implement the following interfaces json.Marshaler, json.Unmarshaler, fmt.Stringer (if you use JSON, if you use
another marshaling format in your application, you will need to implement the required interfaces).

◦ You can use a library to generate those implementations for you.

• iota is a predeclared identifier. It represents successive untyped integer constants.

• We can use it in a “grouped” declaration of constants.

• Its value starts at zero and is equal to the index of the constant.

• A bit is a binary digit (0 or 1)

• A byte is 8 bits.

• Go has bitwise logical and shift operators. We can use them only with integers

& : AND

| :OR

^ :XOR

&^ :AND NOT

<< :left shift

>> :right shift

• An uint8 is stored in memory with 8 bits

• You can use an uint8 to pass a set of 8 boolean arguments to a function or method

◦ We can use bitwise operators to check the value of those boolean arguments.

Bibliography
• [institute1990ieee] Electrical, Institute of, and Electronics Engineers. 1990. “IEEE Standard Glossary of Software Engineering Terminology:
Approved September 28, 1990, IEEE Standards Board.” In. Inst. of Electrical; Electronics Engineers.
• [go-specs] “The Go Programming Language Specification.” n.d. Accessed April 30, 2018. https://golang.org/ref/spec.
• [go-specs] “The Go Programming Language Specification.” n.d. Accessed April 30, 2018. https://golang.org/ref/spec.
• [go-specs] “The Go Programming Language Specification.” n.d. Accessed April 30, 2018. https://golang.org/ref/spec.

18 of 19 02/01/2023, 02:15
Enum, Iota & Bitmask - Practical Go Lessons https://www.practical-go-lessons.com/chap-27-enum-iota-and-bitmask

Previous Next

Basic HTTP Server Dates and time

Table of contents

Did you spot an error ? Want to give me feedback ? Here is the feedback page! ×

Newsletter:
Like what you read ? Subscribe to the newsletter.

I will keep you informed about the book updates.

@ my@email.com

Practical Go Lessons
By Maximilien Andile
Copyright (c) 2023
Follow me Contents
Posts
Book
Support the author Video Tutorial

About
The author
Legal Notice
Feedback
Buy paper or digital copy
Terms and Conditions

19 of 19 02/01/2023, 02:15

You might also like