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
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())
}
}
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)
}
}
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)