第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相关推荐

  1. 《Go语言圣经》第一章:入门-习题解答及读书笔记精华摘要

    1.1 Hello World gopl_hello.go package mainimport ("fmt" )func main() {fmt.Println("He ...

  2. 《Go语言圣经》第一章 - 读书笔记

    <Go语言圣经>第一章 - 读书笔记 第一章 Go语言入门 01 Hello World 02 命令行参数 练习 练习1.1 练习1.2: 练习1.3: 03 查找重复的行 例子运行 du ...

  3. Go语言圣经 - 第3章 基础数据类型

    第3章 基础数据类型 Go语言将数据类型分为了四类:基础类型.符合类型.引用类型和接口类型.基础类型:数字.字符串和布尔型:复合数据类型:数组和结构体:引用类型:指针.切片.字典.函数.通道,虽然数据 ...

  4. Go语言圣经 - 第11章 测试 - 11.1 go test 11.2 测试函数

    第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...

  5. Go语言圣经 - 第10章 包和工具 - 10.7 工具

    第10章 包和工具 现在随便一个小程序可能就包含10000个函数,但是我们不可能一个个去构建,大部分还是来自于他人,这些函数通过类似包和模块的方式被重用 go语言的包超过100个,可以在终端中使用go ...

  6. Go语言圣经 - 第11章 测试 - 11.4 - 11.6

    第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...

  7. Go语言圣经 - 第8章 Goroutines 和 Channels - 8.8 示例:并发的目录遍历

    第8章 Goroutines 和 Channels Go语言中的并发程序可以用两种手段来实现:goroutine 和 channel,其支持顺序通信进程,或被简称为CSP,CSP是一种并发编程模型,在 ...

  8. Go语言圣经 - 第7章 接口 - 7.9 表达式求值

    第7章 接口 接口类型是对其它类型行为的抽象和概括.接口类型不会和特定的实现细节绑定在一起,这种抽象的方式能让我们的函数更加的灵活和更具有适应能力 Go语言的接口比较特殊,因为它是满足隐式实现的.也就 ...

  9. Go语言圣经 - 第11章 测试 - 11.3 测试覆盖率

    第11章 测试 软件测试是一个巨大的领域,但是Go语言的测试技术是相对比较低级的,它依赖一个Go test测试命令和一组按照约定方式编写的测试函数,测试命令可以运行这些函数 在实践中,编写测试代码和编 ...

最新文章

  1. C++利用cin输入时检测回车的方法
  2. 根据信号灯状态解决网络故障
  3. 大疆口袋相机美颜怎么设置_大疆口袋小相机DJI Pocket 2套装版深度评测:变成生产力工具...
  4. 深度学习02——Softmax、DNN、WideDeep Model
  5. linux显示文本文件指定行数的数据
  6. Netty 的 FastThreadLocal 到底快在哪里
  7. 英文参考文献的正确引用格式详解
  8. mongovue 导入mysql_MongoVUE简单操作手册
  9. 开源BI工具 - Superset
  10. 高配置服务器组装电脑,小白DIY装机需睁大眼睛!点评几款网购组装电脑主机配置单...
  11. 周伟焜:IBM为何重造信仰
  12. 编程,初来乍到,多多关照。
  13. 柠檬班软件测试靠谱吗 全程班毕业后7天就拿到了offer
  14. 中基鸿业工薪家庭理财方法
  15. C++中常见的两种二义性问题及其解决方式
  16. 芝诺数解|「八」旅途中的“家”——重庆酒店特征分析
  17. RxJava入门之生命周期管理
  18. Java实验作业11(Math)
  19. 透过现象看本质:共享单车之摩拜和ofo的工作原理分析
  20. 贝壳上市背后的秘密武器-ACN

热门文章

  1. 学习笔记(05):人工智能-必备数学基础视频教程-奇异值的分解
  2. iText7 HTML to PDF 支持中文 支持加粗
  3. PTN设备和SDH设备有什么区别?可以互通吗?
  4. android获取指定号码的短信,如何接收特定号码的短信信息?
  5. android studio忘记密码界面,AndroidStudio制作“我”的界面,设置,修改密码,设置密保和找回密码...
  6. 48个音标,你学会了吗?
  7. Android Wav音频文件裁剪
  8. 抖音小程序拍抖音功能
  9. 最新.net面试题及答案
  10. 程序员怎样铺就薪资之路