The division trap — a 0% book
Now a mistake that does not look like a mistake. Say you have read 190 pages out of 380 and want the progress as a percentage:
progress := it.PagesRead / it.Pages * 100
fmt.Println("Progress:", progress, "%")
The result:
Progress: 0 %
Zero percent. You read half the book and the program says 0 — with no error and no warning. Why? PagesRead and Pages are both int, and integer division throws away the remainder: 190 / 380 = 0 (the whole part), then 0 * 100 = 0. The program computed "correctly" — by int rules.
The cure is an explicit conversion to float64 BEFORE dividing:
progress := float64(it.PagesRead) / float64(it.Pages) * 100
fmt.Printf("Progress: %.1f%%\n", progress)
Progress: 50.0%
Go never converts types silently — an int will not become a float64 on its own. That feels pedantic, but it is exactly why the bug is always visible in the code: wherever there is no float64(...), the division is integer division.
Briefly on characters: a string stores bytes; a rune is one Unicode character. len("ąžuolas") returns bytes (9), not letters (7) — Lithuanian letters take 2 bytes each. If you ever count letters: len([]rune(s)).
Gotcha. The int-division bug is dangerous because it is silent: an expense average, a rating average, a percentage — they all "work", they just show the wrong answer. The rule: when you see
/, ask yourself — do I want the remainder thrown away here? If not, convert tofloat64before the division (not after:float64(a/b)is too late — the division already happened in int world).