Go语言圣经 - 第1章 入门 - 1.3 1.4 查找重复的行 GIF
第1章 入门
1.3 查找重复的行
在1.2节,我们简单的了解了一些Go语言的基本语法,接下来我们再来看一个例子进一步学习
对文件做拷贝、打印、搜索和排序、统计或类似事情的程序都有一个差不多的程序结构:一个处理输入的循环,再每个元素上执行计算处理,在处理的同时或最后产生输出。我们来通过一些案例深入理解下这种程序结构
case 1:
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)}}
}
1)定义一个map类型的变量,map是一个存储了键/值得集合,其中键和值都可以是任意类型,这里创建map使用内置的make函数。map类型在后面我们还会讲到
counts := make(map[string]int)
2)第二个变量input是通过bufio包下的NewScanner函数定义的,我们来对这个函数进行剥洋葱式的了解一下
input:= bufio.NewScanner(os.Stdin)
NewScanner函数有一个参数r,类型是io.Reader,同时返回值是*Scanner, 通过查看函数体我们发现它是一个结构体的引用(当某个变量本身很大,不方便传递时,我们往往选择用指针进行引用而不是直接传递这个变量)
func NewScanner(r io.Reader) *Scanner {return &Scanner{r: r,split: ScanLines,maxTokenSize: MaxScanTokenSize,}
}
让我们继续,io.Reader不是一个基础数据/符合数据类型其它非自定义类型,所以我们还得继续剥洋葱看看它是什么,原来它是io包下的一个interface,interface里面还包含了一个method: Read,Read方法有一个Reader receiver,一个byte切片类型的参数p,返回值是一个int类型和err 接口,接口里面有一个方法Error.到此我们终于剥完了洋葱
其实大体逻辑通常就是:函数里面是接口、接口里面是方法、方法里面是非自定义的变量,当然在更多例子中,我们也会看到函数、接口、甚至更多的自定义类型充满了各种各样的嵌套
type Reader interface {Read(p []byte) (n int, err error)
}
func (Reader) Read(p []byte) (n int, err error)
type error interface {Error() string
}
func (error) Error() string
再回到input这个变量,我们给NewScanner传递了一个变量:os包下的变量Stdin
input:= bufio.NewScanner(os.Stdin)
我们来继续看看它是什么,原来它是newFile函数的返回值,并且是个引用类型,那newFile函数到底干了什么呢,它在函数体内调用了另一个包并且做了一个判断并且返回了引用值
var (Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
)
func NewFile(fd uintptr, name string) *File {h := syscall.Handle(fd)if h == syscall.InvalidHandle {return nil}return newFile(h, name, "file")
}
看了详细的调用过程,我们小结下 bufio 包,它使处理输入和输出方便又高效。 Scanner 类型是该包最有用的特性之 一,它读取输入并将其拆成行或单词;通常是处理行形式的输入最简单的方法。 程序使用短变量声明创建 bufio.Scanner 类型的变量 input 。 input := bufio.NewScanner(os.Stdin) 该变量从程序的标准输入中读取内容。每次调用 input.Scan() ,即读入下一行,并移除行末的换行符;读取的内容可以调用 input.Text() 得到。Scan 函数在读到一行时返回 true ,不再有输入时返回 false
3)两个for循环
在前面我们了解了几个通过自定义、函数的返回值定义的变量(参数),等获得了这些参数后,使用for循环进行处理并输出
for input.Scan(){counts[input.Text()]++}for line,n :=range counts{if n>1{fmt.Printf("%d\t%s\n",n,line)}}
4)fmt.printf函数
fmt.Printf 函数对一些表达式产生格式化输出,下面是常见的格式化输出语法
%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 变量的类型%% 字面上的百分号标志(无操作数)
case 2:
case 2的过程稍微复杂了一点,但是逻辑上和case1是一致的
package mainimport ("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()]++}
}
case 3: 同理
相信有很多同学看到这里已经糊了,不过没没关系,我们可以先尽量看懂case,等学的更深入一点,再回过头来看这些case,就一目了然了
package mainimport ("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.Fprintf(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)}}
}
1.4 GIF动画
我们来继续看个例子,学习更多知识点
package mainimport ("image""image/color""image/gif""io""math""math/rand""os""time"
)var palette = []color.Color{color.White, color.Black}const (whiteIndex = 0blackIndex = 1
)func main() {rand.Seed(time.Now().UTC().UnixNano())lissajous(os.Stdout)
}func lissajous(out io.Writer) {const (cycles =5res =0.001size =100nframes =64delay =8)freq :=rand.Float64()*3.0anim :=gif.GIF{LoopCount: nframes}phase:=0.0for i := 0; i<nframes;i++{rect :=image.Rect(0,0,2*size+1,2*size+1)img:=image.NewPaletted(rect,palette)for t:=0.0;t<cycles*2*math.Pi;t+=res{x:=math.Sin(t)y:=math.Sin(t*freq+phase)img.SetColorIndex(size+int(x*size+0.5),size+int(y*size+0.5),blackIndex)}phase+=0.1anim.Delay = append(anim.Delay,delay)anim.Image = append(anim.Image,img)}gif.EncodeAll(out,&anim)
}
这个例子中,我们使用了结构体、浮点型等数据结构,至于整个程序的逻辑,会比较复杂,这个我们等学习更多Go语言知识再来解释
Go语言圣经 - 第1章 入门 - 1.3 1.4 查找重复的行 GIF相关推荐
- 《Go语言圣经》第一章:入门-习题解答及读书笔记精华摘要
1.1 Hello World gopl_hello.go package mainimport ("fmt" )func main() {fmt.Println("He ...
- 《Go语言圣经》第一章 - 读书笔记
<Go语言圣经>第一章 - 读书笔记 第一章 Go语言入门 01 Hello World 02 命令行参数 练习 练习1.1 练习1.2: 练习1.3: 03 查找重复的行 例子运行 du ...
- Go语言圣经 - 第3章 基础数据类型
第3章 基础数据类型 Go语言将数据类型分为了四类:基础类型.符合类型.引用类型和接口类型.基础类型:数字.字符串和布尔型:复合数据类型:数组和结构体:引用类型:指针.切片.字典.函数.通道,虽然数据 ...
- Go语言圣经 - 第11章 测试 - 11.1 go test 11.2 测试函数
第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...
- Go语言圣经 - 第10章 包和工具 - 10.7 工具
第10章 包和工具 现在随便一个小程序可能就包含10000个函数,但是我们不可能一个个去构建,大部分还是来自于他人,这些函数通过类似包和模块的方式被重用 go语言的包超过100个,可以在终端中使用go ...
- Go语言圣经 - 第11章 测试 - 11.4 - 11.6
第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...
- Go语言圣经 - 第8章 Goroutines 和 Channels - 8.8 示例:并发的目录遍历
第8章 Goroutines 和 Channels Go语言中的并发程序可以用两种手段来实现:goroutine 和 channel,其支持顺序通信进程,或被简称为CSP,CSP是一种并发编程模型,在 ...
- Go语言圣经 - 第7章 接口 - 7.9 表达式求值
第7章 接口 接口类型是对其它类型行为的抽象和概括.接口类型不会和特定的实现细节绑定在一起,这种抽象的方式能让我们的函数更加的灵活和更具有适应能力 Go语言的接口比较特殊,因为它是满足隐式实现的.也就 ...
- Go语言圣经 - 第11章 测试 - 11.3 测试覆盖率
第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...
最新文章
- C++利用cin输入时检测回车的方法
- 根据信号灯状态解决网络故障
- 大疆口袋相机美颜怎么设置_大疆口袋小相机DJI Pocket 2套装版深度评测:变成生产力工具...
- 深度学习02——Softmax、DNN、WideDeep Model
- linux显示文本文件指定行数的数据
- Netty 的 FastThreadLocal 到底快在哪里
- 英文参考文献的正确引用格式详解
- mongovue 导入mysql_MongoVUE简单操作手册
- 开源BI工具 - Superset
- 高配置服务器组装电脑,小白DIY装机需睁大眼睛!点评几款网购组装电脑主机配置单...
- 周伟焜:IBM为何重造信仰
- 编程,初来乍到,多多关照。
- 柠檬班软件测试靠谱吗 全程班毕业后7天就拿到了offer
- 中基鸿业工薪家庭理财方法
- C++中常见的两种二义性问题及其解决方式
- 芝诺数解|「八」旅途中的“家”——重庆酒店特征分析
- RxJava入门之生命周期管理
- Java实验作业11(Math)
- 透过现象看本质:共享单车之摩拜和ofo的工作原理分析
- 贝壳上市背后的秘密武器-ACN
热门文章
- 学习笔记(05):人工智能-必备数学基础视频教程-奇异值的分解
- iText7 HTML to PDF 支持中文 支持加粗
- PTN设备和SDH设备有什么区别?可以互通吗?
- android获取指定号码的短信,如何接收特定号码的短信信息?
- android studio忘记密码界面,AndroidStudio制作“我”的界面,设置,修改密码,设置密保和找回密码...
- 48个音标,你学会了吗?
- Android Wav音频文件裁剪
- 抖音小程序拍抖音功能
- 最新.net面试题及答案
- 程序员怎样铺就薪资之路