- 接上一节任务运行后续
在上一节中 dup1 从标准输入当中获取数据,而在 dup2 当中我们读取标准输入或是使用os.Open打开各个具名文件,并操作它们。
一、dup2
运行路径:
$GOPATH/src/gopl/ch1/dup
运行方式
$ go run dup2.go input.txt
尝试了上述的运行方式,我们得到以下的运行结果
二、程序分析
以下是程序从标准输入或者某个文件中读取数据处理的源代码:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
counts := make(map[string]int)
files := os.Args[1:]
if len(files) == 0 {
countLines(os.Stdin, counts)
}else {
for _,arg := range files {
f, err := os.Open(arg)
if err != nil {
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
}
for line, n := range counts{
if n > 1{
fmt.Printf("%d\t%s\n", n, line)
}
}
}
func countLines(f *os.File, counts map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
counts[input.Text()]++
}
}
1. os.Args中的数组slice
files := os.Args[1:] 表示返回的是输入参数的 数组slice, 类似于引用。在 go 语言当中 ,os.Args[m:n] 表示返回输入参数列表中 [m, n) 个参数的一个 数组slice, os.Args[m:] 表示返回输入参数列表中第m个到最后一个参数的数组slice, os.Args[:n] 表示返回输入参数列表中 [1, n) 个参数的一个 数组slice
2. os.Open
os.Open 函数返回了两个参数,第二个参数是内置 error 类型的值。如果 err 等于内置值 nil ,表示文件打开成功,直到处理完所有数据后, 调用 Close 关闭该文件,并释放所占有的所有资源。反而言之如果 err 的值不是等于 nil 值,就代表打开文件出错,就需要有对应的处理方式.
f, err := os.Open(arg)
if err != nil {
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
continue
}
3. countLines 函数中的map[string]int
map 是一个由 make 函数创建的数据结构的引用。map 作为为参数传递给某函数时,该函数接收这个引用的一份拷贝( copy ,或译为副本),被调用函数对 map 底层数据结构的任何修改,调用者函数都可以通过持有的 map 引用看到。在我们的例子中,countLines 函数向 counts 插入的值,也会被 ** main** 函数看到。(译注:类似于 C++ 里的引用传递,实际上指针是另一个指针了,但内部存的值指向同一块内存)
4. fmt.Printf
类似于 C 或其它语言里的 printf 函数, fmt.Printf 函数对一些表达式产生格式化输出。该函数的首个参数是个格式字符串,指定后续参数被如何格式化。按照惯例,以字母 f 结尾的格式化函数,如 log.Printf 和 fmt.Errorf ,都采用 fmt.Printf 的格式化准则。而以 ln 结尾的格式化函数,则遵循 Println 的方式,以跟 %v 差不多的方式格式化参数,并在最后添加一个换行符。
%d 十进制整数
%x, %o, %b 十六进制,八进制,二进制整数。
%f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00
%t 布尔:true或false
%c 字符(rune) (Unicode码点)
%s 字符串
%q 带双引号的字符串"abc"或带单引号的字符’c’
%v 变量的自然形式(natural format)
%T 变量的类型
%% 字面上的百分号标志(无操作数)
5. for循环中 “_” 的使用
在 for 循环当中我们使用 “_” , 因为 range 对返回了两个参数,第二个参数是 value, 第一个参数就是索引号, “_” 就像是 Linux 中的 /dev/null 一样像个无底洞,
for _,arg := range files {
//_ 代表就是 files 的索引值
}
总结
- 理解 “_” 的含义
- map[string]int的引用传值
- Printf 函数的格式, 特别注意 %v %T
- 理解数组切片