go-concurrency101/3-word-counter/main.go

80 lines
1.2 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strings"
"sync"
)
/*
@Ref: https://livebook.manning.com/book/go-in-practice/chapter-3/65
1. --reac flag is able to do the race detection
2. How to use scanner to split the word in a file
3. sync.Mutex usage
*/
func main() {
wg := sync.WaitGroup{}
w := newWords()
for _, file := range os.Args[1:] {
wg.Add(1)
go func(filename string) {
tallyWords(filename, w)
wg.Done()
}(file)
}
wg.Wait()
fmt.Println("Words that appear more than once:")
for word, count := range w.found {
if count > 1 {
fmt.Printf("%s: %d\n", word, count)
}
}
}
type words struct {
sync.Mutex
found map[string]int
}
func newWords() *words {
return &words{found: make(map[string]int)}
}
func (w *words) add(word string, n int) {
w.Lock()
defer w.Unlock()
count, ok := w.found[word]
if !ok {
w.found[word] = n
return
}
w.found[word] = count + n
}
func tallyWords(filename string, dist *words) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
word := strings.ToLower(scanner.Text())
dist.add(word, 1)
}
return scanner.Err()
}