首页 > 编程语言 > 详细

GO语言实践(2)——第二章

时间:2021-03-17 00:21:42      阅读:33      评论:0      收藏:0      [点我收藏+]

GO语言实践(2)——第二章

  • 可以看到,main 函数保存在名为 main 的包里。如果 main 函数不在 main 包里,构建工 具就不会生成可执行的文件。
package main
import "fmt"
func main(){
	fmt.Println("hello world")
}
  • 一个包定义一组编译 过的代码,包的名字类似命名空间,可以用来间接访问包内声明的标识符。这个特性可以把不同 包中定义的同名标识符区别开

main包

01 package main
02
03 import (
04 "log"
05 "os"
06
07 _ "github.com/goinaction/code/chapter2/sample/matchers"
08 "github.com/goinaction/code/chapter2/sample/search"
09 )
10
11 // init 在 main 之前调用
12 func init() {
13 // 将日志输出到标准输出
14 log.SetOutput(os.Stdout)
15 }
16
17 // main 是整个程序的入口
18 func main() {
19 // 使用特定的项做搜索
20 search.Run("president")
21 }
  • 在这个例子中,由于第 08 行的导入,main.go 里的代码就可以引用 search 包里的 Run 函数。程序的第 04 行和第 05 行导入标准库里的 log 和 os 包。
  • 在第7行中,导入Mathers包前使用了__
    • 这个技术是为了让 Go 语言对包做初始化操作,但是并不使用包里的标识符。为了让程序的 可读性更强,Go 编译器不允许声明导入某个包却不使用。
    • 下划线让编译器接受这类导入,并且 调用对应包内的所有代码文件里定义的 init 函数。对这个程序来说,这样做的目的是调用 matchers 包中的 rss.go 代码文件里的 init 函数,注册 RSS 匹配器,以便后用。
  • main包中也有一个init函数
    • 程序中每个代码文件里的 init 函数都会在 main 函数执行前调用。

Search包

这个包由 4 个不同的代码文件组成。每个文件对应一个独立的职责。

  • 匹配器:
    • 是指包含特定信息、用于处理某类数据源的实例。
    • 框架本 身实现了一个无法获取任何信息的默认匹配器,而在 matchers 包里实现了 RSS 匹配器。RSS 匹配器知道如何获取、读入并查找 RSS 数据源。
01 package search
02
03 import (
04 "log"
05 "sync"
06 )
07
08 // 注册用于搜索的匹配器的映射
09 var matchers = make(map[string]Matcher)

(log 包提供打印日志信息到标准输出(stdout)、标准错误(stderr)或者自定义设备的 功能。sync 包提供同步 goroutine 的功能。这个示例程序需要用到同步功能。)

  • 第9行是全书第一次

    • 这个变量没有定义在任何函数作用域内,所以会被当成包级变量。
    • 这个变量使用关键字 var 声明,而且声明为 Matcher 类型的映射(map),这个映射以 string 类型值作为键,Matcher 类型值作为映射后的值。Matcher 类型在代码文件 matcher.go 中声明,后面再讲这个类型的用 途。这个变量声明还有一个地方要强调一下:变量名 matchers 是以小写字母开头的。
  • 以大写字母开头的标识符属于公开标识符,程序可以直接访问这个包中任意一个公开的标识符。而以小写字母开头的 标识符是不公开的,不能被其他包中的代码直接访问。但是,其他包可以间接访问不公开的标识 符。例如,一个函数可以返回一个未公开类型的值,那么这个函数的任何调用者,哪怕调用者不 是在这个包里声明的,都可以访问这个值。

  • 这个变量声明还使用了赋值运算符和特殊的内置函数make初始化了变量(第9行)

    • map 是 Go 语言里的一个引用类型,需要使用 make 来构造。
    • 在Go语言中,所有的变量都被初始化为其0值。

Run函数

func Run(searchTerm string){
    
}

Go语言使用关键词func声明函数,关键词后面紧跟着函数名、参数、以及返回值。

对于Run这个函数来说,只有一个参数,是string类型的,名为searchTerm。

  • 让我们仔细看看从函数返回的值是如何赋值给变量的
13 // 获取需要搜索的数据源列表
14 feeds, err := RetrieveFeeds()
  • 这里可以看到简化变量声明运算符(:=)。

简化变量声明运算符只是一 种简化记法,让代码可读性更高。这个运算符声明的变量和其他使用关键字 var 声明的变量没 有任何区别。

根据经验,如果需要声明初始值为零值 的变量,应该使用 var 关键字声明变量;如果提供确切的非零值初始化变量或者使用函数返回 值创建变量,应该使用简化变量声明运算符。

22 // 构造一个 wait group,以便处理所有的数据源
23 var waitGroup sync.WaitGroup
24
25 // 设置需要等待处理
26 // 每个数据源的 goroutine 的数量
27 waitGroup.Add(len(feeds))
  • 这个程序使用 sync 包的 WaitGroup 跟踪所有启动的 goroutine。非常推荐使用 WaitGroup 来 跟踪 goroutine 的工作是否完成。WaitGroup 是一个计数信号量,我们可以利用它来统计所有的 goroutine 是不是都完成了工作。
29 // 为每个数据源启动一个 goroutine 来查找结果
30 for _, feed := range feeds {
31 // 获取一个匹配器用于查找
32 matcher, exists := matchers[feed.Type]
33 if !exists {
34 matcher = matchers["default"]
35 }
36
37 // 启动一个 goroutine 来执行搜索
38 go func(matcher Matcher, feed *Feed) {
39 Match(matcher, feed, searchTerm, results)
40 waitGroup.Done()
41 }(matcher, feed)
42 } 
  • 如果仔细看一下第 30 行的 for range 语句,会发现再次使用了下划线标识符,这是第二次看到使用了下划线标识符。第一次是在 main.go 里导入 matchers 包的时候。这 次,下划线标识符的作用是占位符,占据了保存 range 调用返回的索引值的变量的位置。如果 要调用的函数返回多个值,而又不需要其中的某个值,就可以使用下划线标识符将其忽略。

    +++

  • 我们会在第 6 章进一步学习 goroutine,现在只要知道,一个 goroutine 是一个独立于其他函 数运行的函数。

  • 使用关键字 go 启动一个 goroutine,并对这个 goroutine 做并发调度。

  • 在第 41 行,matcher 和 feed 两个变量的值被传入匿名函数。在 Go 语言中,所有的变量 都以值的方式传递。因为指针变量的值是所指向的内存地址,在函数间传递指针变量,是在传递 这个地址值,所以依旧被看作以值的方式在传递。

39 Match(matcher, feed, searchTerm, results)
40 waitGroup.Done()
  • goroutine 做的第一件事是调用一个叫 Match 的函数,这个函数可以在 match.go 文件里找 到。Match 函数的参数是一个 Matcher 类型的值、一个指向 Feed 类型值的指针、搜索项以及 输出结果的通道。我们一会儿再看这个函数的内部细节,现在只要知道,Match 函数会搜索数 据源的数据,并将匹配结果输出到 results 通道。

GO语言实践(2)——第二章

原文:https://www.cnblogs.com/Gumi-o/p/14546545.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!