orion
anderson

Grimoire Entries tagged with “Go”

Example of channels in Go

Channels are communication channels between goroutines. Use channels when you want to pass errors or any other kind of information between goroutines.

Let’s use customers ordering pasta dishes as our scenario.

Each customer places an order for a pasta dish. The dish is assigned a random difficulty and sent to a goroutine (the “kitchen”). The goroutine “makes” the dish, waiting a number of seconds to simulate difficulty before sending the completed dish into a channel.

Our output prints (or “serves”) the dishes in the order in which they were received by the channel.

package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Dish struct {
	pasta, sauce string
	difficulty   int
}

func makeDish(i int, dish Dish, ch chan string) {
	d, p, s := dish.difficulty, dish.pasta, dish.sauce
	time.Sleep(time.Duration(d) * time.Second)
	ch <- fmt.Sprintf(
		"Serving Order #%d\t(Difficulty %d)\t%s %s", i, d, p, s)
}

func main() {

	customers := 5

	pastas := []string{"Rigatoni", "Fettuccine", "Tagliatelle", "Penne"}
	sauces := []string{"Bolognese", "Carbonara", "Alfredo", "Pomodoro"}

	ch := make(chan string, customers)

	rand.Seed(time.Now().UnixNano())

	for i := 1; i <= customers; i++ {
		order := Dish{
			pasta:      pastas[rand.Intn(len(pastas))],
			sauce:      sauces[rand.Intn(len(sauces))],
			difficulty: rand.Intn(11),
		}
		go makeDish(i, order, ch)
	}
	fmt.Println("All orders sent to the kitchen!")
	fmt.Println("Waiting...")

	for 0 < customers {
		dish := <-ch
		fmt.Println(dish)
		customers--
	}

	fmt.Println("All dishes served.")
}

Run on Go Playground

Fizz Buzz in Go

Fizz buzz is a group word game for children to teach them about division. Players take turns to count incrementally, replacing any number divisible by three with the word “fizz”, and any number divisible by five with the word “buzz”.

I wrote this implementation in Go quickly as an answer on LeetCode. The interesting bit is the use of Itoa().

Initially, I tried to convert the counter i to a string with string(). This did not work because string() returns a rune, not a digit.

I also tried fmt.Sprint(), which worked in this simple example. But I wasn’t sure if this method was the best one to use. The fmt package has a ton of methods.

After some research, I learned that the Itoa() method returns the equivalent of FormatInt(int64(x), 10). That is to say, the string of x when the base is 10.

In math, 0, 1, 2, 3, 4, 5, 6, 7, 8, and 9 are base ten numerals. Base-10 is used in most modern civilizations (probably because we have 10 fingers) and forms the basis of our counting system and monetary system.

Generally in Go, Itoa is useful for when you want to create incrementing constants.

The takeaway is that the strconv.Itoa() seems better for counters because it uses base 10 counting and thus is safer for incrementing counter values.

Solution using Itoa()

package main

import (
	"fmt"
	"strconv"
)

func main() {
	for i := 1; i <= 15; i++ {
		output := ""

		if i%3 == 0 {
			output += "Fizz"
		}
		if i%5 == 0 {
			output += "Buzz"
		}
		if output == "" {
			output += strconv.Itoa(i)
		}

		fmt.Println(output)
	}
}

Run on Go Playground

Alternate solution without Itoa():

package main

import (
	"fmt"
)

func main() {
	for i := 1; i <= 15; i++ {
		if i%3 == 0 && i%5 == 0 {
			fmt.Println("FizzBuzz")
		} else if i%3 == 0 && i%5 != 0 {
			fmt.Println("Fizz")
		} else if i%3 != 0 && i%5 == 0 {
			fmt.Println("Buzz")
		} else {
			fmt.Println(i)
		}
	}
}

Run on Go Playground