How to do it...

These steps cover writing and running your application:

  1. From your Terminal or console application, create a new directory called ~/projects/go-programming-cookbook/chapter10/state and navigate to it.
  2. Run the following command:
$ go mod init github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/state

You should see a file called go.mod that contains the following content:

module github.com/PacktPublishing/Go-Programming-Cookbook-Second-Edition/chapter10/state    
  1. Copy the tests from ~/projects/go-programming-cookbook-original/chapter10/state, or use this as an opportunity to write some of your own code!
  2. Create a file called state.go with the following content:
        package state

type op string

const (
// Add values
Add op = "add"
// Subtract values
Subtract = "sub"
// Multiply values
Multiply = "mult"
// Divide values
Divide = "div"
)

// WorkRequest perform an op
// on two values
type WorkRequest struct {
Operation op
Value1 int64
Value2 int64
}

// WorkResponse returns the result
// and any errors
type WorkResponse struct {
Wr *WorkRequest
Result int64
Err error
}
  1. Create a file called processor.go with the following content:
        package state

import "context"

// Processor routes work to Process
func Processor(ctx context.Context, in chan *WorkRequest, out
chan *WorkResponse) {
for {
select {
case <-ctx.Done():
return
case wr := <-in:
out <- Process(wr)
}
}
}
  1. Create a file called process.go with the following content:
        package state

import "errors"

// Process switches on operation type
// Then does work
func Process(wr *WorkRequest) *WorkResponse {
resp := WorkResponse{Wr: wr}

switch wr.Operation {
case Add:
resp.Result = wr.Value1 + wr.Value2
case Subtract:
resp.Result = wr.Value1 - wr.Value2
case Multiply:
resp.Result = wr.Value1 * wr.Value2
case Divide:
if wr.Value2 == 0 {
resp.Err = errors.New("divide by 0")
break
}
resp.Result = wr.Value1 / wr.Value2
default:
resp.Err = errors.New("unsupported operation")
}
return &resp
}
  1. Create a new directory named example and navigate to it.
  2. Create a file named main.go with the following content:
        package main

import (
"context"
"fmt"

"github.com/PacktPublishing/
Go-Programming-Cookbook-Second-Edition/
chapter10/state"
)

func main() {
in := make(chan *state.WorkRequest, 10)
out := make(chan *state.WorkResponse, 10)
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()

go state.Processor(ctx, in, out)

req := state.WorkRequest{state.Add, 3, 4}
in <- &req

req2 := state.WorkRequest{state.Subtract, 5, 2}
in <- &req2

req3 := state.WorkRequest{state.Multiply, 9, 9}
in <- &req3

req4 := state.WorkRequest{state.Divide, 8, 2}
in <- &req4

req5 := state.WorkRequest{state.Divide, 8, 0}
in <- &req5

for i := 0; i < 5; i++ {
resp := <-out
fmt.Printf("Request: %v; Result: %v, Error: %vn",
resp.Wr, resp.Result, resp.Err)
}
}
  1. Run go run main.go.
  2. You may also run the following commands:
$ go build
$ ./example

You should now see the following output:

$ go run main.go
Request: &{add 3 4}; Result: 7, Error: <nil>
Request: &{sub 5 2}; Result: 3, Error: <nil>
Request: &{mult 9 9}; Result: 81, Error: <nil>
Request: &{div 8 2}; Result: 4, Error: <nil>
Request: &{div 8 0}; Result: 0, Error: divide by 0
  1. The go.mod file may be updated and the go.sum file should now be present in the top-level recipe directory.
  2. If you copied or wrote your own tests, go up one directory and run go test. Ensure that all the tests pass.