第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. 基于卷积神经网络(CNN)的仙人掌图像分类
  2. 计算机科学速成课】[40集全/精校] - Crash Course Computer Science
  3. Python2.x与3​​.x版本区别
  4. Spring_hibernate整合初步 based in annotation
  5. CPU方案简介ATS3609D - 智能故事机
  6. 第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波7 - 直方图处理 - 直方图、归一化直方图
  7. 操作word打印网址
  8. 扩展欧几里得算法(双六游戏)
  9. Suggestion: add 'tools:replace=android:value' to meta-data element at AndroidManifest.xml:25:5-2...
  10. 写给对前途迷茫的朋友:五句话定会改变你的人生
  11. 使用Sklearn模型做分类并绘制机器学习模型的ROC曲线
  12. 分享(Java中new一个对象的过程)
  13. 2021雪花飘新年倒计时源码
  14. ubuntu14.04安装Java jdk/jdr虚拟机
  15. Docker——数据卷的概述和使用
  16. C++-----------notify_one()与notify_all()
  17. windows下测试磁盘读写(HD Tune)
  18. java打印日期序列_Java8新特性之新日期API
  19. Programmer-如何从菜鸟变成老鸟?
  20. 金蝶EAS管理控制台一闪而过

热门文章

  1. 探秘AlphaStar:星际争霸人工智能
  2. 【学习笔记】山东大学生物信息学-04 蛋白质结构预测与分析
  3. java calendar 下个月_使用Java中的Calendar类增加一个月
  4. C/C++后端开发面经(1)——计算机操作系统
  5. 2008年8月22号,星期五,晴。丈夫志四海,万里犹比邻。 —— 曹 植《赠白马王彪》今天是我博士生涯的第47天
  6. 直播系统app源码经验分享——直播系统PK功能介绍
  7. 小明发布_LPL纪录片《来者何人》发布 RNG问题明显比FPX严重_国内动态
  8. Linux环境下rabbitMq安装
  9. 轻轻松松运行起minicap
  10. 用友U8财务会计管理的固定资产模块中启用了固定资产,打开提示不属于最新的1899年