day-02 go maps! ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~* date: 2026-09-02 (Wed) agenda: - work on TGPL chapter 1 [] (made it to 1.4) - have fun [x] - draw a gopher [] - gofmt tabs/spaces??? [x] --- # kl. 9.49 gofmt ====== - found out go fmt is more convenient than gofmt (go fmt is gofmt with -l and -w, so it automatically overwrites the file and lists the modified files) - added config to my ~/.confg/nvim/init.lua to deal with go fmt (it forces tabs so we don't want to convert tabs to spaces): vim.api.nvim_create_autocmd({'BufRead', 'BufNewFile'}, { pattern = {'*.go'}, callback = function(ev) vim.opt.expandtab = false vim.o.list = false end }) and to my ~/.vimrc, i just added: > autocmd BufRead,BufNewFile *.go setlocal noexpandtab --- packages, again =============== so, i can have a directory structure like day-02/main.go: > package main > > import "tilde30.6/day-02/dup" > > func main() { > dup.Dup() > } and day-02/dup/dup.go: > package dup > > import "fmt" > > func Dup() { > fmt.Println("test") > } within directory day-02, i run $ go mod init 'tilde30.6/day-02/dup' so the dup package will be available in the main package. then, we can just $ go run . to run the thing (with main as the entry point). note the Dup function has to be capitalised, otherwise it is private. go fmt interjection =================== run $ go fmt tilde30.6/... to run the formatter for the whole, like, module/tree/whatever. TGPL 1.3 Finding Duplicate Lines ================================ cf. day-02/dup/dup1.go this program makes sense! introduces - maps - make - bufio.Scanner * .NewScanner() * .Scan() * .Text() scanner / buffered IO ====================== > input := bufio.NewScanner(os.Stdin) Scanners read input and split it into lines (or words, not sure how to do that yet, lines by default i suppose). yep: => https://pkg.go.dev/bufio@go1.27.1#Scanner.Split > input.Scan(): - returns true iff there is a line, also removes the trailing '\n' TODO: does it handle those old like windows kinda newlines? > input.Text(): - retrieves the current line as string --- run with $ cat test.txt | go run . prints: > 3 duplicates of 'go' > 2 duplicates of 'food' > 2 duplicates of 'gonad' (hash)map ========== i like the map declaration syntax! like, > map[string]int is kinda "declaration follows use" like in C? i.e. if i access a map foo of the given type with a string like foo["oof"], i get an integer. also cool: works kinda like defaultdict in python, i.e. accessing a non-existing element gives the "init" value of the type if used in an expression. fmt.Printf =========== %d decimal integer %x, %o, %b integer in hexadecimal, octal, binary %f, %g, %e floating-point number: 3.141593 3.141592653589793 3.141593e+00 %t boolean: true or false %c rune (Unicode code point) %s string %q quoted string "abc" or rune 'c' %v any value in a natural format %T type of any value %% literal percent sign (no operand) (cf. p. 10) reading files =============== cf. day-02/dup/dup2.go > f, err := os.Open("fname") to open file f (type *os.File) and *os.File can be passed to bufio.NewScanner() > f.Close() yeah. references &c. ============== > A map is a reference to the data structure > created by make. When a map is passed to a > function, the function receives a copy of > the reference cf. p. 12 (the function will mutate the map) io/ioutil ========== use ioutil.ReadFile("fname") to read whole file into memory. > Under the covers, bufio.Scanner, > ioutil.ReadFile, and ioutil.WriteFile use > the Read > and Write methods of *os.File, but it’s > rare that most programmers need to access those > lower-level routines directly. The higher-level > functions like those from bufio and > io/ioutil are easier to use --- Solved Exercise 1.4, pretty ugly but works. That was fun. would have been easier by using map/set instead of adding to a string, but oh well. ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*