第一题
题意:修改echo程序,使其能够打印os.Args[0],即被执行命令本身的名字。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Args[0])
}
第二题
题意:修改echo程序,使其打印每个参数的索引和值,每个一行。
package main
import (
"fmt"
"os"
)
func main() {
for index,arg := range os.Args[0:] {
fmt.Printf("%d : %s\n",index,arg)
}
}
第三题
题意:练习 1.3: 做实验测量潜在低效的版本和使用了 strings.Join 的版本的运行时间差异。(1.6节讲解了部分 time 包,11.4节展示了如何写标准测试程序,以得到系统性的性能评测。)
package practise_test
import (
"strings"
"testing"
)
func StrPlus2(a []string) string {
return strings.Join(a," ")
}
func StrPlus1(a []string) string{
var s,sep string
for i := 0 ; i < len(a) ; i++ {
s += sep + a[i]
sep = " "
}
return s
}
func BenchmarkStrPlus1(b *testing.B) {
for i := 0 ; i < b.N ; i++ {
StrPlus1([]string{"BGM","is","learning","Golang"})
}
}
func BenchmarkStrPlus2(b *testing.B) {
for i := 0 ; i <b.N ; i++ {
StrPlus2([]string{"BGM","is","learning","Golang"})
}
}
测试结果截图:

结果分析:
strings.Join函数做字符串连接效率比直接"+"要高一倍以上。
strings.Join函数的源码:
// Join concatenates the elements of its first argument to create a single string. The separator
// string sep is placed between elements in the resulting string.
func Join(elems []string, sep string) string {
switch len(elems) {
case 0://如果elems长度为0,就返回空字符串
return ""
case 1://如果elems长度为1,就返回唯一的元素
return elems[0]
}
n := len(sep) * (len(elems) - 1)//统计分隔符sep一共需要占用的长度
for i := 0; i < len(elems); i++ {//统计包括elems本身在内的总长度
n += len(elems[i])
}
var b Builder//Builder是一个struct 内部数据用[]byte存储
b.Grow(n)//保证b的[]byte容量大于n
b.WriteString(elems[0])//写第一个元素
for _, s := range elems[1:] {//循环写入sep+elems[i]
b.WriteString(sep)
b.WriteString(s)
}
return b.String()
}
效率提高主要是省掉了字符串"+"操作时每次都重新再分配空间和拷贝复制数据的过程。
第四题
题意:修改dup2,出现重复的行时打印文件名称。
package main
import (
"bufio"
"fmt"
"os"
)
type LNFile struct {
Count int
FileNames []string
}
func main() {
counts := make(map[string]*LNFile)
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)
}
countLines(f,counts)
f.Close()
}
}
for line,n := range counts {
if n.Count > 1 {
fmt.Printf("%d %v\n%s\n",n.Count,n.FileNames,line)
}
}
}
func countLines(f *os.File, counts map[string]*LNFile) {
input := bufio.NewScanner(f)
for input.Scan() {
key := input.Text()
_,ok := counts[key]
if ok {
counts[key].Count++
counts[key].FileNames = append(counts[key].FileNames,f.Name())
} else {
counts[key] = new(LNFile)
counts[key].Count = 1
counts[key].FileNames = append(counts[key].FileNames,f.Name())
}
}
}