1、
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
map 存储一个键/值对集合,并且提供常量时间的操作来存储、获取或测试集合中的某个元素。键可以是其值能够进行相等(==)比较的任意类型,字符串是最常见的例子;值可以是任意类型。为了输出结果,我们使用基于 range 的 for 循环,每次迭代输出两个结果,map 里面一个元素对应的键和值。map 里面的键的迭代顺序不是固定的,通常是随机的,每次运行都不一致。
使用bufio 包,可以简便和高效地处理输入和输出。Scanner 可以读入输入,以行或者单词为单位断开,这是已行为单位的输入内容的最简单方式。
每一次调用 input.Scan() 读取下一行,并且将结尾的换行符去掉;通过调用 input.Text() 来获取读到的内容。Scan 函数在读到新行的时候返回 true ,在没有更多内容的是否返回 false。
Printf 函数有超过10个这样的转义字符,Go 程序员称为 verb。如下
verb 描述
%d 十进制整数
%x,%o,%b 十六进制、八进制、二进制整数
%f,%g,%e 浮点数,如:3.1415926
%t 布尔型,true 或 false
%c 字符(Unicode 码点)
%s 字符串
%q 带引号字符串(如 “abc”)或者字符(‘c’)
%v 内置格式的任何值
%T 任何值的类型
%% 百分号本身(无操作数)
诸如 log.Printf 和 fmt.Errorf 之类的格式化函数已 f 结尾,使用和 fmt.Printf 相同的格式化规则;而那些以 ln 结尾的函数(如 Println) 则使用 %v 的方式来格式化参数,并在最后追加换行符。
2、下面的程序是从文件列表中进行读取,并使用 os.Open 函数来逐个打开。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counters := make(map[string]int)
files := os.Args[1:]
if len(files) == 0 {
counteLines(os.Stdin, counters)
} else {
for _, arg := range files {
f, err := os.Open(arg)
if err != nil {
fmt.Println(os.Stderr, "dump2: %v\n", err)
continue
}
counteLines(f, counters)
f.Close()
}
}
for line, n := range counters {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
func counteLines(f *os.File, counts map[string]int) {
intput := bufio.NewScanner(f)
for intput.Scan() {
counts[intput.Text()]++
}
}
在此代码中, map 是一个使用 make 创建的数据结构的引用。当一个 map 被传递给一个函数时,函数接收到这个引用的副本,所以被调用函数中对于 map 数据结构中的改变对函数调用者使用的 map 引用也是可见的。
3、
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
counts := make(map[string]int)
for _, filename := range os.Args[1:] {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprint(os.Stderr, "dup3: %v\n", err)
continue
}
for _, line := range strings.Split(string(data), "\n") {
counts[line]++
}
}
for line, n := range counts{
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
上面的程序中,引入一个 ReadFile 函数(从 io/ioutil包),它读取整个命名文件的内容,还引入一个 strings.Split 函数,它将字符串分割为一个由字符组成的 slice。