贺胖娇的编程之旅......

go语言圣经-(1)入门-命令行参数、查找重复行

2022.03.07

基本介绍

可以参考此文章:https://docs.hacknode.org/gopl-zh/ch0/ch0-02.html

基础使用

查看go版本

go version

引入代码

需要在环境变量中添加GOPATH目录,然后使用go get 命令下载代码,以下为《go语言圣经》的示例

export GOPATH=$HOME/go    # 选择工作目录
go get gopl.io/ch1/helloworld # 获取/编译/安装
$GOPATH/bin/helloworld        # 运行程序

执行代码

执行代码使用go run命令

go run hello.go

编译代码

编译代码使用go build命令,执行完后会生成一个可执行文件,在windows会生成一个exe文件

go build hello.go

main包和main函数的特殊性

main包比较特殊。它定义了一个独立可执行的程序,而不是一个库。
在main里的main 函数 也很特殊,它是整个程序执行时的入口(译注:C系语言差不多都这样)。
main函数所做的事情就是程序做的。当然了,main函数一般调用其它包里的函数完成很多工作, 比如, fmt.Println。

代码示例

可以直接参考(2)go基础学习-基本使用

命令行参数

在文档中给出的示例是:

package main

import (
	"fmt"
	"os" //os包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从os包的Args变量获取;os包外部使用os.Args访问该变量。
)
func main()  {
	var s, sep string
	for i := 0; i < len(os.Args); i++ {
		s += sep + os.Args[i]
		sep = " " //添加空格属于二次加工,参数数量庞大时开销很大
	}
	fmt.Println(s)
}

对于string类型,+表示连接字符串(与js和C++语法相同)

for循环

for循环有多种形式

for initialization; condition; post {
    // zero or more statements
}
// a traditional "while" loop
for condition {
    // ...
}
// a traditional infinite loop,可以通过break或return终止循环
for {
    // ...
}

for循环在range中遍历,修改以上示例为:

package main

import (
	"fmt"
	"os"
)

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

使用循环来拼接字符串代价高昂,一种简单且高效的解决方案是使用strings包的Join函数

package main

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

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

如果不关心输出格式,可以直接输出:

package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println(os.Args[1:])
}

练习题

练习1.2

修改echo程序,使其打印每个参数的索引和值,每个一行。

package main

import (
	"fmt"
	"os"
)

func main() {
	for key, val := range(os.Args[1:]) {
		fmt.Println(key)
		fmt.Println(val)
	}
}

练习1.3

做实验测量潜在低效的版本和使用了strings.Join的版本的运行时间差异。(1.6节讲解了部分time包,11.4节展示了如何写标准测试程序,以得到系统性的性能评测。)

简单实现

package main

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

func main() {
	firstStart := time.Now().Nanosecond()

	var s1, sep string
	for i := 1; i < len(os.Args); i++ {
		s1 += sep + os.Args[i]
		sep = " "
	}
	fmt.Println(s1)
	firstEnd := time.Now().Nanosecond()
	timeSpace := firstEnd - firstStart
	fmt.Println("%.2fs long time space: ", timeSpace)
	secondStart := time.Now().Nanosecond()
	fmt.Println(strings.Join(os.Args[1:], " "))
	secondEnd := time.Now().Nanosecond()
	timeSpace2 := secondEnd - secondStart
	fmt.Println("%.2fs short time space: ", timeSpace2)
}

加上测试

todo… #查找重复的行

从标准输入中读入数据

可以对重复行计数,从标准输入中读入数据,输入ctrl+D结束并运行

package main

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

func main()  {
	counts := make(map[string]int) //map[key][val]

	input := bufio.NewScanner(os.Stdin)

	for input.Scan() {
		counts[input.Text()]++
	}
	for k, v := range counts {
		if v > 1 {
			fmt.Println("val %s key %d", k, v)
		}
	}
}

从文件中读入数据

读取标准输入或是使用os.Open打开各个具名文件,并操作它们

/**
1 获取所有参数,若未获取到,直接获取输入内容进行比较
2 获取到了则打开文件
3 获取行数
 */
package main

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

func main()  {
	counts := make(map[string]int)
	files := os.Args[1:]

	if len(files) < 1 {
		compareByMap(os.Stdin, counts)
	} else {
		for _, args := range files {
			f, err := os.Open(args)
			if err != nil {
				fmt.Fprintf(os.Stderr,"err is: %v", err) //任意类型默认格式值的动词%v
				continue
			}
			f.Close()
			compareByMap(f, counts)
		}
	}
	for key, val := range counts {
		if val > 1 {
			fmt.Printf("名称:%s出现了%d次\n", key, val)
		}
	}
}

func compareByMap(f *os.File, counts map[string]int) {
	input := bufio.NewScanner(f)
	for input.Scan() {
		counts[input.Text()]++
	}
}

一次性读取文件全部数据

/**
1 只读文件,不读标准输入
2 读取文件内容,并做错误处理
3 \n切割文件内容并放入map中
4 出现次数大于1则输出
 */
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

func main()  {
	counts := make(map[string]int)
	files := os.Args[1:]

	for _, arg := range files {
		file, err := ioutil.ReadFile(arg) //ReadFile函数返回一个字节切片
		if err != nil {
			fmt.Fprintf(os.Stderr, "error:%v\n", err)
			continue
		}
		for _, line := range strings.Split(string(file), "\n") {
			counts[line]++
		}
	}
	for key, val := range counts {
		if val > 1 {
			fmt.Printf("参数%s出现了%d次\n", key, val)
		}
	}
}
发表评论