Skip to content
0

入门

Echo 程序

echo 程序实现了输出命令行参数的功能。

go
package main

import (
	"fmt"
	"os"
	"strings"
	"time"
)

func main() {
	// 三种不同的实现方式
	echoFor()
	echoForRange()
	echoJoin()

	// 打印程序名
	echo()

	// 打印索引和值
	echoForRangeKV()

	// 简单的使用 time 包对比不同实现的性能
	echoForTime()
	echoForRangeTime()
	echoJoinTime()
}

func echoFor() {
	var s, sep string
	for _, arg := range os.Args[1:] {
		s += sep + arg
		sep = " "
	}
	fmt.Println(s)
}

func echoForRange() {
	var s, sep string
	for _, arg := range os.Args[1:] {
		s += sep + arg
		sep = " "
	}
	fmt.Println(s)
}

func echoJoin() {
	fmt.Println(strings.Join(os.Args[1:], " "))
}

func echo() {
	fmt.Println(os.Args[0])
}

func echoForRangeKV() {
	for i, arg := range os.Args[1:] {
		fmt.Printf("index: %d, value: %s\n", i+1, arg)
	}
}

func echoForTime() {
	start := time.Now()
	var s, sep string
	for _, arg := range os.Args[1:] {
		s += sep + arg
		sep = " "
	}
	fmt.Println(s)
	fmt.Println(time.Since(start))
}

func echoForRangeTime() {
	start := time.Now()
	var s, sep string
	for _, arg := range os.Args[1:] {
		s += sep + arg
		sep = " "
	}
	fmt.Println(s)
	fmt.Println(time.Since(start))
}

func echoJoinTime() {
	start := time.Now()
	fmt.Println(strings.Join(os.Args[1:], " "))
	fmt.Println(time.Since(start))
}

运行 echo 程序:

bash
a b c
a b c
a b c
/var/folders/3n/7gjxlkgd5216cxw0gx9lzf9m0000gn/T/go-build929972194/b001/exe/main
index: 1, value: a
index: 2, value: b
index: 3, value: c
a b c
21.167µs
a b c
1.916µs
a b c
1.667µs

三种不同的实现方式的性能对比:

  • echoFor:使用 for 循环遍历命令行参数,每次迭代拼接一个参数,最后输出结果。
  • echoForRange:使用 for range 循环遍历命令行参数,每次迭代拼接一个参数,最后输出结果。
  • echoJoin:使用 strings.Join 函数将命令行参数拼接成一个字符串,最后输出结果。

从运行结果可以看出,echoJoin 的性能最优,而 echoForRange 的性能次之,echoFor 的性能最差。

Dup 程序

dup 程序实现了统计标准输入中重复出现的行的功能。

go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	dupStdin()
	dupStdinOrFile()
}

func dupStdin() {
	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)
		}
	}
}

func dupStdinOrFile() {
	counts := make(map[string]int)
	files := os.Args[1:]
	if len(files) == 0 {
		countLines(os.Stdin, counts)
	} else {
		for _, filename := range files {
			file, err := os.Open(filename)
			if err != nil {
				fmt.Fprintf(os.Stderr, "dup: %v\n", err)
				continue
			}
			countLines(file, counts)
			file.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()]++
	}
}

运行 dup 程序:

bash
#!/bin/bash
# 方法1: 直接输入文本,按Ctrl+D结束输入
echo "=== 方法1: 直接输入文本 ==="
echo "运行程序后,输入几行文本,然后按Ctrl+D结束输入"
echo "例如:"
echo "hello"
echo "world"
echo "hello"
echo "然后按Ctrl+D"

# 方法2: 通过管道从文件读取
echo -e "\n=== 方法2: 通过管道从文件读取 ==="
echo "cat sample.txt | go run ch01/dup/main.go"
echo "输出结果:"
cat sample.txt | go run ch01/dup/main.go

# 方法3: 通过重定向输入
echo -e "\n=== 方法3: 通过重定向输入 ==="
echo "go run ch01/dup/main.go < sample.txt"
echo "输出结果:"
go run ch01/dup/main.go < sample.txt

sample.txt

text
hello
world
hello
go
programming
world
hello
最近更新