听峰问雨 听峰问雨
首页
导航站
  • 编程语言

    • Python
  • 数据结构与算法
  • 设计模式
  • UVA
  • LeetCode
  • 《Go语言实战》
  • 《Go Web编程》
  • 《算法精粹 经典计算机科学问题的Python实现》
  • 学习
  • 博客搭建
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
GitHub (opens new window)

zfprotectors

默默学习er
首页
导航站
  • 编程语言

    • Python
  • 数据结构与算法
  • 设计模式
  • UVA
  • LeetCode
  • 《Go语言实战》
  • 《Go Web编程》
  • 《算法精粹 经典计算机科学问题的Python实现》
  • 学习
  • 博客搭建
  • 本站

    • 分类
    • 标签
    • 归档
  • 我的

    • 收藏
    • 关于
GitHub (opens new window)
  • 《Go语言实战》

    • Go语言的介绍
    • 快速开始一个Go程序-RSS匹配器
      • 程序架构
      • main包
      • search包
      • RSS匹配器
      • 总结
    • 打包和工具链
    • 数组,切片和映射
    • Go语言的类型系统
    • 并发
  • 《Go Web编程》

  • 《算法精粹 经典计算机科学问题的Python实现》

  • 读书笔记
  • 《Go语言实战》
zfprotectors
2022-05-25
目录

快速开始一个Go程序-RSS匹配器

通过一个Go语言程序,来学习相应的语法规则。这个程序从不同的数据源拉取数据,并将数据内容与一组搜索项做对比,然后将匹配的内容显示在终端窗口上。

# 程序架构

项目结构:

sample
├── data
│   └── data.json
├── main.go
├── matchers
│   └── rss.go
└── search
    ├── default.go
    ├── feed.go
    ├── match.go
    └── search.go

1
2
3
4
5
6
7
8
9
10
11
12

data.json:包含一组程序要拉取和处理的数据源

rss.go:搜索rss源的匹配器

default.go:搜索数据用的默认匹配器

feed.go:用于读取json数据文件

match.go:用于支持不同匹配器的接口

search.go:执行搜索的主控制逻辑

main.go:程序的入口

# main包

// main.go
package main

import (
	"log"
	"os"

	_ "./matchers"
	"./search"
)

// init 在main之前调用
func init() {
	// 将日志输出到标准输出
	log.SetOutput(os.Stdout)
}

// main是整个程序的入口
func main() {
	// 使用特定的项做搜索
	search.Run("president")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  • 包:Go语言的每个代码文件都属于一个包,一个包定义一组编译过的代码,包的名字类似命名空间,可以用来间接访问包内声明的标识符。
    • 所有在同一个文件夹里的代码文件,必须使用同一个包名(包和文件夹同名)。
    • 标准库中导入代码时,只需要给出要导入的包名
    • 编译器查找第三方包的时候,会到GOROOT和GOPATH环境变量引用的位置去查找
  • 导入:import就是导入一段代码,当你在其他地方实现了功能,你可以使用该方法将函数调用过来。
    • 第7行中存在一个_,可以让Go语言对该包做初始化操作,但是不导入包里的内容,该目的就是调用 matchers 包中的rss.go文件里的init函数
  • init初始化函数:程序中每个代码文件里的init函数都会在main函数执行前调用
  • main函数:在main函数中,调用了search包里的Run函数

# search包

这个包由4个不同的代码文件组成。

提示

首先理解什么是匹配器,匹配器,是指包含特定信息,用于处理某类数据源的实例。

// search/search.go
package search

import (
	"log"
	"sync"
)

// 注册用于搜索的匹配器的映射
var matchers = make(map[string]Matcher)

// Run执行搜索逻辑
func Run(searchTerm string) {
    // 获取需要搜索的数据源列表
	feeds, err := RetrieveFeeds()
	if err != nil {
		log.Fatal(err)
	}

    // 创建一个无缓冲的通道,用来接收匹配后的记过
	results := make(chan *Result)

	// 构造一个wait group, 用来处理所有的数据源。
	var waitGroup sync.WaitGroup

    // 设置需要等待的同奥
    // 每个数据源的goroutine的数量.
	waitGroup.Add(len(feeds))

    // 为每个数据源启动一个goroutine来查找结果
	for _, feed := range feeds {
        // 收到一个匹配用来查找
		matcher, exists := matchers[feed.Type]
		if !exists {
			matcher = matchers["default"]
		}

        // 启动一个goroutine来执行搜索
		go func(matcher Matcher, feed *Feed) {
			Match(matcher, feed, searchTerm, results)
			waitGroup.Done()
		}(matcher, feed)
	}

    // 启动一个goroutine来监控所有的工作是否完成了
	go func() {
        // 等待所有任务完成
		waitGroup.Wait()

        // 关闭通道的方式来执行显示函数,最后退出程序。
		close(results)
	}()

    // 显示结果
	Display(results)
}

// Register is called to register a matcher for use by the program.
func Register(feedType string, matcher Matcher) {
	if _, exists := matchers[feedType]; exists {
		log.Fatalln(feedType, "Matcher already registered")
	}

	log.Println("Register", feedType, "matcher")
	matchers[feedType] = matcher
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  • 变量:使用关键字var声明。
    • 变量没有定义在任何函数作用域内,就会被当成包级变量
    • 需要声明初始值的零值的变量,应该使用var关键字声明变量
  • 声明运算符(:=):这个运算符用于声明一个变量,同时给变量赋予初始值。
    • 编译器使用函数返回值的类型来确定每个变量的类型
    • 简化只是一种简化记法,如果提供非零值初始化变量或者使用函数返回值创建变量,应该是使用简化变量声明运算符(:=)。
  • 当代码导入了一个包时,程序可以直接访问这个包中的任何一个公开的标识符。
    • 公开的这些标识符以大写字母开头,可以理解为public。
    • 小写字母开头的标识符就是不公开的,可以理解为private。
  • 零值:所有变量都会被初始化为零值
    • 数值类型,零值为0
    • 字符串类型,零值为""
    • 指针,零值为nil
    • 引用类型,根据引用的底层数据结构进行初始化对应的零值
  • 函数声明:使用关键字func声明函数,关键字后面紧跟着函数名, 参数和返回值
  • 引用类型
    • 映射:map是Go语言中的一个引用类型,需要使用make来构造,而map变量的默认的零值为nil。
    • 切片:slice是一种实现了动态数组的引用类型
    • 通道:channel也是引用类型
  • 一个函数可以返回多个值。一般像RetrieveFeed函数一样,一个函数返回一个值和一个错误值。

针对项目而言,在main函数返回后,整个程序就会终止,同时也会关闭之前启动但还在正常运行的goroutine。因此,在返回之前,清理并终止所有之前启动的goroutine

  • 使用sync包里的WaitGroup跟踪所有启动的goroutine
  • 其中waitGroup是一个计数信号量,用于统计所有的goroutine是不是完成了工作。当WaitGroup变量的计数值,当这个值减少为0时,所有的工作即完成了。

# RSS匹配器

# 总结

编辑 (opens new window)
#Go
上次更新: 2022/05/26, 12:36:19
Go语言的介绍
打包和工具链

← Go语言的介绍 打包和工具链→

最近更新
01
LeetCode88 - 合并两个有序数组
06-22
02
LeetCode1 - 两数之和
06-22
03
LeetCode1603 - 设计停车系统
06-21
更多文章>
Theme by Vdoing | Copyright © 2021-2022 zfprotectors | 闽ICP备2021014222号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式