DEV Community

taijidude
taijidude

Posted on

My first go at go... would you do anything different?

Hello for a slightly longer article. :-) I had my first try at go program and wanted to share what i have learned.

The tool: I started using obsidian notes and i'am building my self and electronic bullet journal.

Here are the links. But i will probably write about this in a later article:

https://obsidian.md/
https://bulletjournal.com/

In the bullet journal method you have a monthly overview of things. This is basicly a list of you of the number of the day and the weekday besides it. You use this list to write notes about your appointments for that month down.

Example:
01 - sa
02 - su 3 pm cake and Coffee
03 - mo

It's a little tedious to write this down by hand and the use case is easy enough to try this in a new language. I wanted to create a cli tool, which prints a list of days and their respective weekdays for the month i give as parameter when executing the tool.

Example:

.\printMonths.exe -month=january
----january----
01 - sa
02 - su
03 - mo
04 - tu
05 - we
06 - th
07 - fr
08 - sa
09 - su
10 - mo
11 - tu
12 - we
13 - th
14 - fr
15 - sa
16 - su
17 - mo
18 - tu
19 - we
20 - th
21 - fr
22 - sa
23 - su
24 - mo
25 - tu
26 - we
27 - th
28 - fr
29 - sa
30 - su
31 - mo
Enter fullscreen mode Exit fullscreen mode

So here is, what i came up with...

package main

import (
    "errors"
    "flag"
    "fmt"
)

const (
    MONDAY    string = "monday"
    TUESDAY          = "tuesday"
    WEDNESDAY        = "wednesday"
    THURSDAY         = "thursday"
    FRIDAY           = "friday"
    SATURDAY         = "saturday"
    SUNDAY           = "sunday"
)

// Struct to encapsulate the names of the weekdays and
// possibly use them in functions
type WeekData struct {
    days [7]string
}

//this struct holds the data needed to start the print of the days
type MonthData struct {
    numberOfDays int
    startDay     string
    weekData     WeekData
}

//logic for the printing of the days
func (m MonthData) print() string {
    result := ""
    currentWeekday := m.startDay
    for day := 1; day <= m.numberOfDays; day++ {
        result = result + fmt.Sprintf("%02d", day) + " - " + currentWeekday[0:2] + "\n"
        var err error
        currentWeekday, err = m.weekData.next(currentWeekday)
        if err != nil {
            fmt.Println(err)
            return ""
        }
    }
    return result
}

//gets you the next day
func (w WeekData) next(current string) (string, error) {
    if current == SUNDAY {
        return MONDAY, nil
    }
    for index, day := range w.days {
        if day == current {
            return w.days[index+1], nil
        }
    }
    return "", errors.New("Day " + current + " not found")
}

func main() {
    //the weekdata struct is used in the month data struct
    wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}

    //a number of month data structs mapped to the name of the months
    data := map[string]MonthData{
        "january":   MonthData{numberOfDays: 31, startDay: SATURDAY, weekData: wd},
        "febuary":   MonthData{numberOfDays: 28, startDay: TUESDAY, weekData: wd},
        "march":     MonthData{numberOfDays: 31, startDay: TUESDAY, weekData: wd},
        "april":     MonthData{numberOfDays: 30, startDay: FRIDAY, weekData: wd},
        "mai":       MonthData{numberOfDays: 31, startDay: SUNDAY, weekData: wd},
        "june":      MonthData{numberOfDays: 30, startDay: WEDNESDAY, weekData: wd},
        "july":      MonthData{numberOfDays: 31, startDay: FRIDAY, weekData: wd},
        "august":    MonthData{numberOfDays: 31, startDay: MONDAY, weekData: wd},
        "september": MonthData{numberOfDays: 30, startDay: THURSDAY, weekData: wd},
        "october":   MonthData{numberOfDays: 31, startDay: SATURDAY, weekData: wd},
        "november":  MonthData{numberOfDays: 30, startDay: TUESDAY, weekData: wd},
        "december":  MonthData{numberOfDays: 31, startDay: THURSDAY, weekData: wd},
    }

    month := flag.String("month", "default", "month to pick")
    flag.Parse()
    fmt.Println("----" + *month + "----")
    if *month != "" {
        fmt.Print(data[*month].print())
    }
}

Enter fullscreen mode Exit fullscreen mode

And the Tests:

package main

import (
    "testing"
)

func TestNext(t *testing.T) {
    wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}

    nextDay, _ := wd.next(MONDAY)

    if nextDay != TUESDAY {
        t.Errorf("Expected '"+TUESDAY+"', got '%s'", nextDay)
    }
}

func TestPrint(t *testing.T) {

    wd := WeekData{[7]string{MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}}
    md := MonthData{numberOfDays: 1, startDay: SATURDAY, weekData: wd}

    result := md.print()
    if result != "01 - sa\n" {
        t.Errorf("Expected '01 - sa\n', got '%s'", result)
    }

    md = MonthData{numberOfDays: 3, startDay: SATURDAY, weekData: wd}
    result = md.print()
    if result != "01 - sa\n02 - su\n03 - mo\n" {
        t.Errorf("Expected '01 - sa\n02 - su\n03 - mo\n', got '%s'", result)
    }
}

Enter fullscreen mode Exit fullscreen mode

The lessons

  • I had some problems remembering that you can give back multiple values from function. This made stumble when i tried to nest function calls.

  • As far as i understand it the basic go testing package has no assertion. You have to make the test fail yourself.

  • In Java i would create an enum for the weekdays. Im not sure if i handled it the best way here.

  • I need to get a better understanding of pointers. I tried to use string pointers in the functions, to just have one string for each day. But i still get confused.

  • I was fun and go is starting to grow on me. At the first look a lot of convience/code sugar is missing, but i'm sure i need to get more into the language to understand the concepts behind it better and not just write java in go.

What would change in the code above?

Top comments (0)