From bc2a616cff9a1b1e269550e23165f2d3cfcba12b Mon Sep 17 00:00:00 2001 From: chao Date: Thu, 21 Nov 2019 10:12:45 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=A6=E4=B9=A0?= =?UTF-8?q?=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 0 chapter1/channels/hellochannels.go | 0 chapter10/listing01/listing01.go | 0 chapter10/listing02/listing02.go | 0 chapter10/listing03/listing03.go | 0 chapter10/listing04/listing04.go | 0 chapter10/listing05/listing05.go | 0 chapter10/listing06/listing06.go | 0 chapter10/listing06/pubsub/pubsub.go | 0 chapter2/sample/data/data.json | 0 chapter2/sample/main.go | 33 ++++++- chapter2/sample/matchers/rss.go | 0 chapter2/sample/search/default.go | 37 +++++++- chapter2/sample/search/feed.go | 35 +++++-- chapter2/sample/search/match.go | 16 +++- chapter2/sample/search/search.go | 94 ++++++++++++++++--- chapter3/dbdriver/main.go | 0 chapter3/dbdriver/postgres/postgres.go | 0 chapter3/wordcount/gowords.txt | 0 chapter3/wordcount/wordcount.go | 0 chapter3/words/count.go | 0 chapter5/listing11/listing11.go | 0 chapter5/listing34/listing34.go | 0 chapter5/listing35/listing35.go | 0 chapter5/listing36/listing36.go | 0 chapter5/listing46/listing46.go | 0 chapter5/listing48/listing48.go | 0 chapter5/listing50/listing50.go | 0 chapter5/listing56/listing56.go | 0 chapter5/listing60/listing60.go | 0 chapter5/listing64/counters/counters.go | 0 chapter5/listing64/listing64.go | 0 chapter5/listing68/counters/counters.go | 0 chapter5/listing68/listing68.go | 0 chapter5/listing71/entities/entities.go | 0 chapter5/listing71/listing71.go | 0 chapter5/listing74/entities/entities.go | 0 chapter5/listing74/listing74.go | 0 chapter6/listing01/listing01.go | 0 chapter6/listing04/listing04.go | 0 chapter6/listing07/listing07.go | 0 chapter6/listing09/listing09.go | 0 chapter6/listing13/listing13.go | 0 chapter6/listing15/listing15.go | 0 chapter6/listing16/listing16.go | 0 chapter6/listing20/listing20.go | 0 chapter6/listing22/listing22.go | 0 chapter6/listing24/listing24.go | 0 chapter7/patterns/pool/main/main.go | 0 chapter7/patterns/pool/pool.go | 0 chapter7/patterns/runner/main/main.go | 0 chapter7/patterns/runner/runner.go | 0 chapter7/patterns/search/main/main.go | 0 chapter7/patterns/search/search.go | 0 chapter7/patterns/search/searchers.go | 0 chapter7/patterns/semaphore/semaphore.go | 0 chapter7/patterns/work/main/main.go | 0 chapter7/patterns/work/work.go | 0 chapter8/listing03/listing03.go | 0 chapter8/listing11/listing11.go | 0 chapter8/listing24/listing24.go | 0 chapter8/listing27/listing27.go | 0 chapter8/listing29/listing29.go | 0 chapter8/listing31/listing31.go | 0 chapter8/listing37/listing37.go | 0 chapter8/listing46/listing46.go | 0 chapter9/listing01/listing01_test.go | 0 chapter9/listing08/listing08_test.go | 0 chapter9/listing12/listing12_test.go | 0 chapter9/listing17/handlers/handlers.go | 0 .../handlers/handlers_example_test.go | 0 chapter9/listing17/handlers/handlers_test.go | 0 chapter9/listing17/listing17.go | 0 chapter9/listing28/listing28_test.go | 0 74 files changed, 187 insertions(+), 28 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 chapter1/channels/hellochannels.go mode change 100644 => 100755 chapter10/listing01/listing01.go mode change 100644 => 100755 chapter10/listing02/listing02.go mode change 100644 => 100755 chapter10/listing03/listing03.go mode change 100644 => 100755 chapter10/listing04/listing04.go mode change 100644 => 100755 chapter10/listing05/listing05.go mode change 100644 => 100755 chapter10/listing06/listing06.go mode change 100644 => 100755 chapter10/listing06/pubsub/pubsub.go mode change 100644 => 100755 chapter2/sample/data/data.json mode change 100644 => 100755 chapter2/sample/main.go mode change 100644 => 100755 chapter2/sample/matchers/rss.go mode change 100644 => 100755 chapter2/sample/search/default.go mode change 100644 => 100755 chapter2/sample/search/feed.go mode change 100644 => 100755 chapter2/sample/search/match.go mode change 100644 => 100755 chapter2/sample/search/search.go mode change 100644 => 100755 chapter3/dbdriver/main.go mode change 100644 => 100755 chapter3/dbdriver/postgres/postgres.go mode change 100644 => 100755 chapter3/wordcount/gowords.txt mode change 100644 => 100755 chapter3/wordcount/wordcount.go mode change 100644 => 100755 chapter3/words/count.go mode change 100644 => 100755 chapter5/listing11/listing11.go mode change 100644 => 100755 chapter5/listing34/listing34.go mode change 100644 => 100755 chapter5/listing35/listing35.go mode change 100644 => 100755 chapter5/listing36/listing36.go mode change 100644 => 100755 chapter5/listing46/listing46.go mode change 100644 => 100755 chapter5/listing48/listing48.go mode change 100644 => 100755 chapter5/listing50/listing50.go mode change 100644 => 100755 chapter5/listing56/listing56.go mode change 100644 => 100755 chapter5/listing60/listing60.go mode change 100644 => 100755 chapter5/listing64/counters/counters.go mode change 100644 => 100755 chapter5/listing64/listing64.go mode change 100644 => 100755 chapter5/listing68/counters/counters.go mode change 100644 => 100755 chapter5/listing68/listing68.go mode change 100644 => 100755 chapter5/listing71/entities/entities.go mode change 100644 => 100755 chapter5/listing71/listing71.go mode change 100644 => 100755 chapter5/listing74/entities/entities.go mode change 100644 => 100755 chapter5/listing74/listing74.go mode change 100644 => 100755 chapter6/listing01/listing01.go mode change 100644 => 100755 chapter6/listing04/listing04.go mode change 100644 => 100755 chapter6/listing07/listing07.go mode change 100644 => 100755 chapter6/listing09/listing09.go mode change 100644 => 100755 chapter6/listing13/listing13.go mode change 100644 => 100755 chapter6/listing15/listing15.go mode change 100644 => 100755 chapter6/listing16/listing16.go mode change 100644 => 100755 chapter6/listing20/listing20.go mode change 100644 => 100755 chapter6/listing22/listing22.go mode change 100644 => 100755 chapter6/listing24/listing24.go mode change 100644 => 100755 chapter7/patterns/pool/main/main.go mode change 100644 => 100755 chapter7/patterns/pool/pool.go mode change 100644 => 100755 chapter7/patterns/runner/main/main.go mode change 100644 => 100755 chapter7/patterns/runner/runner.go mode change 100644 => 100755 chapter7/patterns/search/main/main.go mode change 100644 => 100755 chapter7/patterns/search/search.go mode change 100644 => 100755 chapter7/patterns/search/searchers.go mode change 100644 => 100755 chapter7/patterns/semaphore/semaphore.go mode change 100644 => 100755 chapter7/patterns/work/main/main.go mode change 100644 => 100755 chapter7/patterns/work/work.go mode change 100644 => 100755 chapter8/listing03/listing03.go mode change 100644 => 100755 chapter8/listing11/listing11.go mode change 100644 => 100755 chapter8/listing24/listing24.go mode change 100644 => 100755 chapter8/listing27/listing27.go mode change 100644 => 100755 chapter8/listing29/listing29.go mode change 100644 => 100755 chapter8/listing31/listing31.go mode change 100644 => 100755 chapter8/listing37/listing37.go mode change 100644 => 100755 chapter8/listing46/listing46.go mode change 100644 => 100755 chapter9/listing01/listing01_test.go mode change 100644 => 100755 chapter9/listing08/listing08_test.go mode change 100644 => 100755 chapter9/listing12/listing12_test.go mode change 100644 => 100755 chapter9/listing17/handlers/handlers.go mode change 100644 => 100755 chapter9/listing17/handlers/handlers_example_test.go mode change 100644 => 100755 chapter9/listing17/handlers/handlers_test.go mode change 100644 => 100755 chapter9/listing17/listing17.go mode change 100644 => 100755 chapter9/listing28/listing28_test.go diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/chapter1/channels/hellochannels.go b/chapter1/channels/hellochannels.go old mode 100644 new mode 100755 diff --git a/chapter10/listing01/listing01.go b/chapter10/listing01/listing01.go old mode 100644 new mode 100755 diff --git a/chapter10/listing02/listing02.go b/chapter10/listing02/listing02.go old mode 100644 new mode 100755 diff --git a/chapter10/listing03/listing03.go b/chapter10/listing03/listing03.go old mode 100644 new mode 100755 diff --git a/chapter10/listing04/listing04.go b/chapter10/listing04/listing04.go old mode 100644 new mode 100755 diff --git a/chapter10/listing05/listing05.go b/chapter10/listing05/listing05.go old mode 100644 new mode 100755 diff --git a/chapter10/listing06/listing06.go b/chapter10/listing06/listing06.go old mode 100644 new mode 100755 diff --git a/chapter10/listing06/pubsub/pubsub.go b/chapter10/listing06/pubsub/pubsub.go old mode 100644 new mode 100755 diff --git a/chapter2/sample/data/data.json b/chapter2/sample/data/data.json old mode 100644 new mode 100755 diff --git a/chapter2/sample/main.go b/chapter2/sample/main.go old mode 100644 new mode 100755 index c1d3b7c..237acaa --- a/chapter2/sample/main.go +++ b/chapter2/sample/main.go @@ -1,21 +1,50 @@ package main +//main 函数保存在名为main的的包里 +//不在 构建工具不会生成可执行的文件 +//每个代码文件都属于一个包 +//@一个包定义一组编译过的代码,包的名字类似命名空间,可以用来间接访问包内生命的标示符。 +//@这个特性把不同的包中的同名标识符区分开 -import ( + +//-sample 外部目录 +// -data +// data.json --数据源 +// - matachers +// rss.go --搜索rss源的匹配器 +// -search +// default.go --搜索默认匹配起 +// feed.go --用于读取json数据的文件 +// match.go --用于支持不同匹配器的接口 +// search.go --执行搜索的主控制逻辑 +// main.go -- 程序的入口 + +import (//import 导入一段代码 "log" "os" _ "github.com/goinaction/code/chapter2/sample/matchers" + //_ 下划线 为了让go对包进行初始化 但是并不使用包里的标识符 + //因为不允许声明不使用 下划线 让编译器接收这类导入, + //并调用对应的包的init函数 + //目的是调用matcher中的rss.go的init()函数 "github.com/goinaction/code/chapter2/sample/search" -) +)//导入search 可以使用search中的run函数 + +//疑问🤔️ search里的init是声明时间执行的 // init is called prior to main. +//在main之前调用 +//标准错误 stderr 标准输出stdout func init() { // Change the device for logging to stdout. + //将日志输出到标准输出 log.SetOutput(os.Stdout) } // main is the entry point for the program. +//输口文件 func main() { // Perform the search for the specified term. + //使用特定索索项目 search的run函数 search.Run("president") } diff --git a/chapter2/sample/matchers/rss.go b/chapter2/sample/matchers/rss.go old mode 100644 new mode 100755 diff --git a/chapter2/sample/search/default.go b/chapter2/sample/search/default.go old mode 100644 new mode 100755 index 3aa083a..8d56ba9 --- a/chapter2/sample/search/default.go +++ b/chapter2/sample/search/default.go @@ -1,15 +1,44 @@ package search - +//search 包 // defaultMatcher implements the default matcher. -type defaultMatcher struct{} +type defaultMatcher struct{} //使用空结构体声明 +//defaultMatcher 类型的结构 +//空结构体 不会分配内存 很适合不需要维护状态的类型 // init registers the default matcher with the program. -func init() { +func init() {//函数将默认匹配器注册到程序里 var matcher defaultMatcher Register("default", matcher) } // Search implements the behavior for the default matcher. +//Search 实现默认匹配器的行为 func (m defaultMatcher) Search(feed *Feed, searchTerm string) ([]*Result, error) { - return nil, nil + //search 返回的nil + return nil, nil } +//defaultMatcher类型实现 +//func (m defaultMatcher) Search +//如果声明函数的时候带有接收者,则意味着声明了一个方法。 +//这个方法会和指定的接收者的类型绑定在一起 +//Search方法 与defaultMatcher 类型值绑定在一起。 +//可以使用defaultMatcher 类型的值或者指向这个类型的指针来调用search方法 +//无论是接收者类型的值来调用这个方法,还是使用者类型值的指针来调用这个方法 +//编译器都会正确的引用对应的值,作为接收者传递给search方法 +//例子 绑定使用 + +//--受限制 +//声明为使用指向defaultMatcher类型的指针作为接受者 +// func (m *defaultMatcher) Search(feed *Feed, searchTerm string) +// //通过interface类型的值来调用方法 +// var dm defaultMatcher +// var matcher Matcher = dm//将值赋值为接口类型 +// matcher.Search(feed, "test")//使用值来调用接口方法 + +//--通过 +// func (m defaultMatcher) Search(feed *Feed, searchTerm strin) +// //通过interface类型的值来调用方法 +// var dm defaultMatcher +// var matcher Matcher =&dm//指针赋值给接口类型 +// matcher.Search(feed, "test")//指针来调用接口 +// \ No newline at end of file diff --git a/chapter2/sample/search/feed.go b/chapter2/sample/search/feed.go old mode 100644 new mode 100755 index ee254ae..716a9db --- a/chapter2/sample/search/feed.go +++ b/chapter2/sample/search/feed.go @@ -1,36 +1,57 @@ package search - -import ( +//包 search +import (//引用 库 "encoding/json" "os" ) const dataFile = "data/data.json" +//定义常量 常量不用指定类型 小写 不对外暴露 // Feed contains information we need to process a feed. -type Feed struct { - Name string `json:"site"` +//结构类型 对外暴露Feed +type Feed struct {//包含要处理的袁书记信息 + Name string `json:"site"`//字符串 类型 `` 标记 URI string `json:"link"` Type string `json:"type"` + `` 标记 tag描述json 解码的源数据 用于Feed切片 } // RetrieveFeeds reads and unmarshals the feed data file. +//search 调用该方法 读取json文件装入到feeds中feed是Feed的切片 func RetrieveFeeds() ([]*Feed, error) { + //没有参数,会返回两个值 Feed切片 和error 表示是否成功 // Open the file. - file, err := os.Open(dataFile) + file, err := os.Open(dataFile)//打开数据文件 + //返回指针,指向File类型的值,第二个返回error类型值 if err != nil { return nil, err } - + //返回Feed切片,切片是动态数组的引用类型 + //切片可以操作一组数据,第二个返回值是是不是错误 // Schedule the file to be closed once // the function returns. defer file.Close() + //defer关键字 会安排随后的函数调用在函数返回时执行 + //使用完文件后要主动关闭文件 + //defer 是在return之后执行关闭cloase以外崩溃也会调用 // Decode the file into a slice of pointers // to Feed values. - var feeds []*Feed + var feeds []*Feed//定义切片 + //声明 feeds 值是nil 的切片 包含一组指向Feed类型值的指针 * + //这个切片的每一项是一个指向一个Feed类型的指针 err = json.NewDecoder(file).Decode(&feeds) + //json包的NewDecoder函数 返回值上调用Decode方法 + //open返回的文件句柄file调用NewDecoder函数得到一个指向Decoder类型值的的指针 + //之后再调用这个(Decoder)指针的Decode方法,传入切片的地址 + //Decode方法会解码数据 把值以Feed类型值形式存入切片 + //Decode 实现/usr/local/Cellar/go/1.12.9/libexec/src/encoding/json/stream.go:52 + // func (dec *Decoder) Decode(v interface{}) error { + // Dcode 方法接受一个类型为 interface{}的值作为参考 + // interface 比较特殊 一般会配合 reflect 包里提供反射功能一起使用 // We don't need to check for errors, the caller can do this. return feeds, err + //调用者会检查错误 } diff --git a/chapter2/sample/search/match.go b/chapter2/sample/search/match.go old mode 100644 new mode 100755 index 3627d98..d3e6a5b --- a/chapter2/sample/search/match.go +++ b/chapter2/sample/search/match.go @@ -1,10 +1,11 @@ package search - +//search包 import ( "log" ) // Result contains the result of a search. +//保存搜索结果 type Result struct { Field string Content string @@ -12,9 +13,18 @@ type Result struct { // Matcher defines the behavior required by types that want // to implement a new search type. -type Matcher interface { +//Matcher 定义了要实现的 新的搜索类型行为 +type Matcher interface {//接口类型 + //Search 方法 指向Result 类型值的指针切片 和一个错误值 Search(feed *Feed, searchTerm string) ([]*Result, error) -} +}//Result 在上面已经声明 + +//interface 接口类型关键字 +//这个接口类型声明了结构类型或者具名类型需要实现的行为 +//接口的行为最终由在这个接口类型中声明的方法来决定 +//interface 类型只包含一个方法 这个类型以er结尾 +//如果包含多个名字需要和行为关联 +//如何实现? 要实现接口类型里声明的所有方法 =>default.go // Match is launched as a goroutine for each individual feed to run // searches concurrently. diff --git a/chapter2/sample/search/search.go b/chapter2/sample/search/search.go old mode 100644 new mode 100755 index df84cf4..124afe3 --- a/chapter2/sample/search/search.go +++ b/chapter2/sample/search/search.go @@ -1,58 +1,128 @@ package search - +//package +包名字 +//search 文件夹下都以search作为包名 import ( - "log" - "sync" -) + "log"//导入log sync包 stdout stderr + "sync"//标准库 同步goroutine功能 +)//编译器查找包时会到Goroot Gopath环境变量的引用位置去查找 // A map of registered matchers for searching. +//注册搜索的匹配器的映射 var matchers = make(map[string]Matcher) +// matchers没有在任何作用域内,是包级变量 +//关键var声明 小写开头,非公开 var声明是初始化为零0的 +//make 构造map类型 map是一个引用类型要用make构造 +//map 默认的零值是nil 不构造直接用报错 +//类型是map 映射以string类型值作为键 +// Matacher类型值作为映射后的值 +//Matcher 类型代表文件matcher.go中的声明 type Matcher{} + +//@所有变量初始化为其零值。数值是0,字符串空字符串,布尔类型,false,指针,nil +//@引用类型引用的底层数据结构被初始化为零值 +//声明为其零值的引用类型返回nil + +// @标识符(变量)要么从包里公开,要么不从包里公开 +// @大写标识符公开,小写字母开头的不公开,不能被其他包中代码直接访问 +// 可以使用一个反问未公开类型的值的函数进行问访问 非公开的标识符 // Run performs the search logic. -func Run(searchTerm string) { +//func 声明函数 +//func 函数名(参数,返回值) +func Run(searchTerm string) {//一个string类型参数 // Retrieve the list of feeds to search through. + //获取资源数据列表RetrieveFeeds()方法在feed中 feeds, err := RetrieveFeeds() + //:= 变量声明运算符 声明并赋值 + //search.RetrieveFeeds([]*fedds,error) + //如果错误调用Log.fatal函数 if err != nil { log.Fatal(err) } + //函数返回错误和另一个值,如果返回错误则不要使用另一个值 // Create an unbuffered channel to receive match results to display. + //make 一个chan无缓冲区通道 接收匹配结果 results := make(chan *Result) + //如果声明初始化为0的使用var 关键字 + //如果非零的或函数函数返回的使用简化声明运算符 := - // Setup a wait group so we can process all the feeds. - var waitGroup sync.WaitGroup + //channel map slice 都是引用类型 + // Setup a wait group so we can process all the feeds. + var waitGroup sync.WaitGroup//处理所有的数据源 + //sync.WaitGroup跟踪所有启动的goroutine + //WaitGroup是一个技术信号量,统计goroutine是否完成了 + // waitGroup 类型变量 // Set the number of goroutines we need to wait for while + //设置需要等待处理 每个数据源的goroutine数量 // they process the individual feeds. waitGroup.Add(len(feeds)) + //设置waitGroup 值为要启动的goroutine的数量 + //goroutine完成后会 递减waitGroup的变量计数值 为0时完成 // Launch a goroutine for each feed to find the results. + //为每个数据源启动一个goroutine来查找结果 + //feed matcher 会随着循环迭代而改变 for _, feed := range feeds { + //关键字 for range 对feeds切片迭代 + //range用于迭代数组,字符串,切片,映射,通道 + //for range 返回两个第一个是索引位置,第二个是值的副本 + //_ 下划线 用来占位 + // Retrieve a matcher for the search. + //获取一个匹配器来查找 根据数据源类型查找一个匹配器值 + //给下面的goroutine使用 matcher, exists := matchers[feed.Type] + //map检查是否含有数据的类型 + //查找map里的键时,要么赋值给一个变量, + //要么精确查找赋值给两个变量 + //2个变量时 第一个值就是查找结果,第二时布尔标志位, + //不存在返回 零值 ,存在返回键所对应值的副本 if !exists { matcher = matchers["default"] - } + }//不存在使用默认匹配器 // Launch the goroutine to perform the search. + //启动一个goroutine 来执行搜索 + //匿名函数 👇 两个变量参数 matcher feed指针 + // go func(matcher Matcher, feed *Feed) { + //go关键字 启动goroutine 做并发调度 + //Match.go 中的Match函数 + //match函数参数matcher 指向Feed的指针,搜索项 通道 + //疑问🤔️searchTerm是怎么使用的 Match(matcher, feed, searchTerm, results) - waitGroup.Done() - }(matcher, feed) + waitGroup.Done()//闭包,函数可以访问没有作为参数传入的变量 + //waitgroup的值没有作为参数传入 + //通过闭包访问的searchTerm, results + // 是访问外层函数作用域中声明这些变量的本身 + //因为matcher feed 每次都变,但是goroutine闭包会共享相同的 + //变量,导致使用同一个matcher来处理同一个feed + //为了避免这个问题使用参数传递 + }(matcher, feed)//两个值 传入匿名函数 + //每次matcher feed 都不一样 所以没用闭包方式访问 + //指针变量方便的在函数内部共享数据,可以让函数访问并修改一个变量的状态 + //这个变量可以在其他函数或goroutine里声明 + //go所有变量都是值传递 + //指针变量指向内存地址,函数间传递指针变量,在传递地址值 } // Launch a goroutine to monitor when all the work is done. - go func() { + //一个goroutine来监控是否都完成了 + go func() {//匿名函数 使用闭包访问waitGroup 和results变量 // Wait for everything to be processed. - waitGroup.Wait() + waitGroup.Wait()//递减计数 // Close the channel to signal to the Display + //results 之前定义了 用关闭通道的方式 通知display函数 可以退出了 // function that we can exit the program. close(results) }() + //main函数返回那么整个程序就终止了,终止前关闭所有的goroutine // Start displaying results as they are available and // return after the final result is displayed. + //调用match的display函数 Display(results) } diff --git a/chapter3/dbdriver/main.go b/chapter3/dbdriver/main.go old mode 100644 new mode 100755 diff --git a/chapter3/dbdriver/postgres/postgres.go b/chapter3/dbdriver/postgres/postgres.go old mode 100644 new mode 100755 diff --git a/chapter3/wordcount/gowords.txt b/chapter3/wordcount/gowords.txt old mode 100644 new mode 100755 diff --git a/chapter3/wordcount/wordcount.go b/chapter3/wordcount/wordcount.go old mode 100644 new mode 100755 diff --git a/chapter3/words/count.go b/chapter3/words/count.go old mode 100644 new mode 100755 diff --git a/chapter5/listing11/listing11.go b/chapter5/listing11/listing11.go old mode 100644 new mode 100755 diff --git a/chapter5/listing34/listing34.go b/chapter5/listing34/listing34.go old mode 100644 new mode 100755 diff --git a/chapter5/listing35/listing35.go b/chapter5/listing35/listing35.go old mode 100644 new mode 100755 diff --git a/chapter5/listing36/listing36.go b/chapter5/listing36/listing36.go old mode 100644 new mode 100755 diff --git a/chapter5/listing46/listing46.go b/chapter5/listing46/listing46.go old mode 100644 new mode 100755 diff --git a/chapter5/listing48/listing48.go b/chapter5/listing48/listing48.go old mode 100644 new mode 100755 diff --git a/chapter5/listing50/listing50.go b/chapter5/listing50/listing50.go old mode 100644 new mode 100755 diff --git a/chapter5/listing56/listing56.go b/chapter5/listing56/listing56.go old mode 100644 new mode 100755 diff --git a/chapter5/listing60/listing60.go b/chapter5/listing60/listing60.go old mode 100644 new mode 100755 diff --git a/chapter5/listing64/counters/counters.go b/chapter5/listing64/counters/counters.go old mode 100644 new mode 100755 diff --git a/chapter5/listing64/listing64.go b/chapter5/listing64/listing64.go old mode 100644 new mode 100755 diff --git a/chapter5/listing68/counters/counters.go b/chapter5/listing68/counters/counters.go old mode 100644 new mode 100755 diff --git a/chapter5/listing68/listing68.go b/chapter5/listing68/listing68.go old mode 100644 new mode 100755 diff --git a/chapter5/listing71/entities/entities.go b/chapter5/listing71/entities/entities.go old mode 100644 new mode 100755 diff --git a/chapter5/listing71/listing71.go b/chapter5/listing71/listing71.go old mode 100644 new mode 100755 diff --git a/chapter5/listing74/entities/entities.go b/chapter5/listing74/entities/entities.go old mode 100644 new mode 100755 diff --git a/chapter5/listing74/listing74.go b/chapter5/listing74/listing74.go old mode 100644 new mode 100755 diff --git a/chapter6/listing01/listing01.go b/chapter6/listing01/listing01.go old mode 100644 new mode 100755 diff --git a/chapter6/listing04/listing04.go b/chapter6/listing04/listing04.go old mode 100644 new mode 100755 diff --git a/chapter6/listing07/listing07.go b/chapter6/listing07/listing07.go old mode 100644 new mode 100755 diff --git a/chapter6/listing09/listing09.go b/chapter6/listing09/listing09.go old mode 100644 new mode 100755 diff --git a/chapter6/listing13/listing13.go b/chapter6/listing13/listing13.go old mode 100644 new mode 100755 diff --git a/chapter6/listing15/listing15.go b/chapter6/listing15/listing15.go old mode 100644 new mode 100755 diff --git a/chapter6/listing16/listing16.go b/chapter6/listing16/listing16.go old mode 100644 new mode 100755 diff --git a/chapter6/listing20/listing20.go b/chapter6/listing20/listing20.go old mode 100644 new mode 100755 diff --git a/chapter6/listing22/listing22.go b/chapter6/listing22/listing22.go old mode 100644 new mode 100755 diff --git a/chapter6/listing24/listing24.go b/chapter6/listing24/listing24.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/pool/main/main.go b/chapter7/patterns/pool/main/main.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/pool/pool.go b/chapter7/patterns/pool/pool.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/runner/main/main.go b/chapter7/patterns/runner/main/main.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/runner/runner.go b/chapter7/patterns/runner/runner.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/search/main/main.go b/chapter7/patterns/search/main/main.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/search/search.go b/chapter7/patterns/search/search.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/search/searchers.go b/chapter7/patterns/search/searchers.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/semaphore/semaphore.go b/chapter7/patterns/semaphore/semaphore.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/work/main/main.go b/chapter7/patterns/work/main/main.go old mode 100644 new mode 100755 diff --git a/chapter7/patterns/work/work.go b/chapter7/patterns/work/work.go old mode 100644 new mode 100755 diff --git a/chapter8/listing03/listing03.go b/chapter8/listing03/listing03.go old mode 100644 new mode 100755 diff --git a/chapter8/listing11/listing11.go b/chapter8/listing11/listing11.go old mode 100644 new mode 100755 diff --git a/chapter8/listing24/listing24.go b/chapter8/listing24/listing24.go old mode 100644 new mode 100755 diff --git a/chapter8/listing27/listing27.go b/chapter8/listing27/listing27.go old mode 100644 new mode 100755 diff --git a/chapter8/listing29/listing29.go b/chapter8/listing29/listing29.go old mode 100644 new mode 100755 diff --git a/chapter8/listing31/listing31.go b/chapter8/listing31/listing31.go old mode 100644 new mode 100755 diff --git a/chapter8/listing37/listing37.go b/chapter8/listing37/listing37.go old mode 100644 new mode 100755 diff --git a/chapter8/listing46/listing46.go b/chapter8/listing46/listing46.go old mode 100644 new mode 100755 diff --git a/chapter9/listing01/listing01_test.go b/chapter9/listing01/listing01_test.go old mode 100644 new mode 100755 diff --git a/chapter9/listing08/listing08_test.go b/chapter9/listing08/listing08_test.go old mode 100644 new mode 100755 diff --git a/chapter9/listing12/listing12_test.go b/chapter9/listing12/listing12_test.go old mode 100644 new mode 100755 diff --git a/chapter9/listing17/handlers/handlers.go b/chapter9/listing17/handlers/handlers.go old mode 100644 new mode 100755 diff --git a/chapter9/listing17/handlers/handlers_example_test.go b/chapter9/listing17/handlers/handlers_example_test.go old mode 100644 new mode 100755 diff --git a/chapter9/listing17/handlers/handlers_test.go b/chapter9/listing17/handlers/handlers_test.go old mode 100644 new mode 100755 diff --git a/chapter9/listing17/listing17.go b/chapter9/listing17/listing17.go old mode 100644 new mode 100755 diff --git a/chapter9/listing28/listing28_test.go b/chapter9/listing28/listing28_test.go old mode 100644 new mode 100755 From 9b7f5e44d2fa99004815c66ded7a52a120059fae Mon Sep 17 00:00:00 2001 From: chao Date: Thu, 21 Nov 2019 23:15:34 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E7=AB=A0=E7=AC=94?= =?UTF-8?q?=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter2/README.md | 39 ++++++++++ chapter2/sample/matchers/rss.go | 35 ++++++--- chapter2/sample/rss.xml | 14 ++++ chapter2/sample/search/default.go | 22 ++++++ chapter2/sample/search/match.go | 17 +++-- chapter2/sample/search/search.go | 6 +- chapter3/READMe.md | 98 ++++++++++++++++++++++++++ chapter3/dbdriver/main.go | 2 +- chapter3/dbdriver/postgres/postgres.go | 2 +- chapter4/README.md | 9 +++ 10 files changed, 226 insertions(+), 18 deletions(-) create mode 100644 chapter2/README.md create mode 100644 chapter2/sample/rss.xml create mode 100644 chapter3/READMe.md create mode 100644 chapter4/README.md diff --git a/chapter2/README.md b/chapter2/README.md new file mode 100644 index 0000000..3398d64 --- /dev/null +++ b/chapter2/README.md @@ -0,0 +1,39 @@ +# README + +## 代码目录 + + ``` + /-sample 外部目录 + /-data + data.json --数据源 + /-matachers + rss.go --搜索rss源的匹配器 + /-search + default.go --搜索默认匹配起 + feed.go --用于读取json数据的文件 + match.go --用于支持不同匹配器的接口 + search.go --执行搜索的主控制逻辑 + main.go -- 程序的入口 + rss.xml -- 示例rss文档 RSS匹配器会下载这些RSS文档。 并将这些返回给results通道 + ``` + +第二章介绍的的是一个rss 匹配程序内容,介绍从每个代码片段介绍语法规则及现象,介绍众多的使用方法和具体实例。 + +## 小结 + +- 每个代码文件都属于一个包,报名应该与代码文件所在文件夹同名 + 每个文件下面的文件头部都必须明确写 package + 文件夹名字 +- 多种初始化方式和声明的变量的方式 如果值没有显式初始化,会默认为零/nil + var 初始化那些是空的变量 + := 初始化赋值 也会有类型推断 +- 指针可以在函数或者goroutine间共享数据 + 例子在search.go 的Run函数中 go func +- 通过启动goroutine和使用通道完成并发和同步 + search.go 使用sync.WaitGroup方法 +- 内置函数支持Go语言内部数据结构 + make方法的使用初始化 引用类型的数据比如 + make(map[string]Matcher) + make(chan *Result) +- 标准库包含很多包 +- Go接口可以编写通用的代码和框架 + 接口里面定义方法,单一方法使用er结尾,多个使用相关名字 diff --git a/chapter2/sample/matchers/rss.go b/chapter2/sample/matchers/rss.go index 3585454..f79df82 100755 --- a/chapter2/sample/matchers/rss.go +++ b/chapter2/sample/matchers/rss.go @@ -1,5 +1,5 @@ package matchers - +//包名 import ( "encoding/xml" "errors" @@ -7,12 +7,13 @@ import ( "log" "net/http" "regexp" - +//标准库 和search包 "github.com/goinaction/code/chapter2/sample/search" ) type ( // item defines the fields associated with the item tag + //item 根据item字段的标签,将定义的字段与rss文档字段关联起来 // in the rss document. item struct { XMLName xml.Name `xml:"item"` @@ -26,6 +27,7 @@ type ( // image defines the fields associated with the image tag // in the rss document. + //根据image字段标签将定义的字段与rss文档字段关联起来 image struct { XMLName xml.Name `xml:"image"` URL string `xml:"url"` @@ -35,6 +37,7 @@ type ( // channel defines the fields associated with the channel tag // in the rss document. + //根据channel 字段标签,将定义的字段与rss文档的字段关联起来 channel struct { XMLName xml.Name `xml:"channel"` Title string `xml:"title"` @@ -51,6 +54,7 @@ type ( } // rssDocument defines the fields associated with the rss document. + //rssDocument定义了与rss文档关联的字段 rssDocument struct { XMLName xml.Name `xml:"rss"` Channel channel `xml:"channel"` @@ -58,9 +62,10 @@ type ( ) // rssMatcher implements the Matcher interface. +// rssMatcher实现了Matcher 接口 type rssMatcher struct{} -// init registers the matcher with the program. +// init registers the matcher with the program. 匹配器注册到程序里 func init() { var matcher rssMatcher search.Register("rss", matcher) @@ -68,7 +73,8 @@ func init() { // Search looks at the document for the specified search term. func (m rssMatcher) Search(feed *search.Feed, searchTerm string) ([]*search.Result, error) { - var results []*search.Result + var results []*search.Result//声明一个值为nil的切片 + //每个切片都指向Result类型值的指针 log.Printf("Search Feed Type[%s] Site[%s] For URI[%s]\n", feed.Type, feed.Name, feed.URI) @@ -79,18 +85,22 @@ func (m rssMatcher) Search(feed *search.Feed, searchTerm string) ([]*search.Resu } for _, channelItem := range document.Channel.Item { + //依次访问内部每一项 // Check the title for the search term. matched, err := regexp.MatchString(searchTerm, channelItem.Title) + 使用regexp包里的MatchString函数对channelItem里的title进行搜索 匹配 if err != nil { return nil, err } // If we found a match save the result. - if matched { + if matched {//如果值为真 + //使用append 将结果加倒入results切片 + //append内置函数会根据切片需要决定是否增加切片的长度和容量 results = append(results, &search.Result{ Field: "Title", Content: channelItem.Title, - }) + })//加入到切片里的是指向Results类型值的指针,取地址用& 最终将指针存入切片 } // Check the description for the search term. @@ -112,29 +122,36 @@ func (m rssMatcher) Search(feed *search.Feed, searchTerm string) ([]*search.Resu } // retrieve performs a HTTP Get request for the rss feed and decodes the results. +//get请求rss数据源并解码 +//小写名字 没有对外暴露 func (m rssMatcher) retrieve(feed *search.Feed) (*rssDocument, error) { if feed.URI == "" { return nil, errors.New("No rss feed uri provided") } // Retrieve the rss feed document from the web. + //从网络获取rss数据源文档 resp, err := http.Get(feed.URI) if err != nil { return nil, err - } + }//http.Get返回一个指向Response 类型的指针 // Close the response once we return from the function. + //一旦函数返回 关闭返回的响应链接 defer resp.Body.Close() // Check the status code for a 200 so we know we have received a - // proper response. + // proper response. 检查状态码200 是不是收到了正确响应 if resp.StatusCode != 200 { return nil, fmt.Errorf("HTTP Response Error %d\n", resp.StatusCode) } // Decode the rss feed document into our struct type. + //将rss数据源文档解码到我们定义的结构类型里 不需要检查错误调用者会做 // We don't need to check for errors, the caller can do this. - var document rssDocument + var document rssDocument //document 类型的rssDocument + //传入局部变量document 地址并返回 err = xml.NewDecoder(resp.Body).Decode(&document) + //NewDecoder 函数返回一个指向Decoder值的指针,之后调用指针的Decode方法 return &document, err } diff --git a/chapter2/sample/rss.xml b/chapter2/sample/rss.xml new file mode 100644 index 0000000..aae221e --- /dev/null +++ b/chapter2/sample/rss.xml @@ -0,0 +1,14 @@ + +News + ... + ... +en +Copyright 2014 NPR - For Personal Use +... + + +Putin Says He'll Respect Ukraine Vote But U.S. + + +The White House and State Department have called on the + \ No newline at end of file diff --git a/chapter2/sample/search/default.go b/chapter2/sample/search/default.go index 8d56ba9..e08e7f2 100755 --- a/chapter2/sample/search/default.go +++ b/chapter2/sample/search/default.go @@ -6,10 +6,15 @@ type defaultMatcher struct{} //使用空结构体声明 //空结构体 不会分配内存 很适合不需要维护状态的类型 // init registers the default matcher with the program. +//被引用时 会被编译器发现,保证在main函数前调用 func init() {//函数将默认匹配器注册到程序里 var matcher defaultMatcher + //创建一个defaultMatcher类型值 传递给 search.go register函数 Register("default", matcher) } +//将一个matcher值保存到注册匹配的映射中 +//会在main函数之前被完成。 +//init 可以完美的完成这种初始化注册的任务 // Search implements the behavior for the default matcher. //Search 实现默认匹配器的行为 @@ -25,8 +30,25 @@ func (m defaultMatcher) Search(feed *Feed, searchTerm string) ([]*Result, error) //可以使用defaultMatcher 类型的值或者指向这个类型的指针来调用search方法 //无论是接收者类型的值来调用这个方法,还是使用者类型值的指针来调用这个方法 //编译器都会正确的引用对应的值,作为接收者传递给search方法 + + + //例子 绑定使用 +//--->调用方法的例子 +//方法声明为使用defaultMatcher类型的值作为接受者 +//func (m defaultMatcher) Search(feed *Feed, searchTerm string) +//生命一个指向defaultMatcher类型的指针 +//dm := new (defaultMatcher) +//dm.Search(feed, "test")//编译器会揭开dm指针的引用,使用对应的值调用方法 +//方法为使用指向defaultMater类型的指针作为接受者 +//func (m *defaultMatcher) Search(feed *Feed, searchTerm string) +//var dm defaultMatcher//声明一个 defaultMatcher类型的值 +//dm.Search(feed, "test")//编译器会自动生成指针引用dm值,使用指针调用方法 +//因大部分方法在调用后都需要维护接受者的状态,所以在一个最佳实践是,将方法的接收者声明为指针 +//对于defaultMatcher类型来说使用值作为接收者是因为创建defaultMatcher类型的值不需要分配聂村 +//由于defaultMatcher不需要维护状态,所以不需要指针像是接受者 +//<----- 👇🤔️没大明白需要测试执行 //--受限制 //声明为使用指向defaultMatcher类型的指针作为接受者 // func (m *defaultMatcher) Search(feed *Feed, searchTerm string) diff --git a/chapter2/sample/search/match.go b/chapter2/sample/search/match.go index d3e6a5b..7923591 100755 --- a/chapter2/sample/search/match.go +++ b/chapter2/sample/search/match.go @@ -27,25 +27,30 @@ type Matcher interface {//接口类型 //如何实现? 要实现接口类型里声明的所有方法 =>default.go // Match is launched as a goroutine for each individual feed to run -// searches concurrently. +//为每个数据源单独启动goroutine来执行这个函数 +// searches concurrently. 并发地执行搜索 +//Matcher 类型的值作为第一个参数 只有实现了Matcher接口的值或指针才能被接收 func Match(matcher Matcher, feed *Feed, searchTerm string, results chan<- *Result) { - // Perform the search against the specified matcher. + // Perform the search against the specified matcher. 对特定匹配器执行搜索 searchResults, err := matcher.Search(feed, searchTerm) - if err != nil { + // 使用实现了Matcher接口的函数的值或指针进行搜索 + if err != nil {//判断是否为错误 log.Println(err) return } - // Write the results to the channel. + // Write the results to the channel. 结果写入通道 for _, result := range searchResults { - results <- result - } + results <- result //结果写入通道 + }//写入结果 --关闭通道--处理结果串在一起 } // Display writes results to the console window as they +// 从每个goroutine接收结果后在终端打印 // are received by the individual goroutines. func Display(results chan *Result) { // The channel blocks until a result is written to the channel. + //通道会一直被阻塞,直到有结果写入 一旦通道被关闭 for循环就终止 // Once the channel is closed the for loop terminates. for result := range results { log.Printf("%s:\n%s\n\n", result.Field, result.Content) diff --git a/chapter2/sample/search/search.go b/chapter2/sample/search/search.go index 124afe3..e6e1ae3 100755 --- a/chapter2/sample/search/search.go +++ b/chapter2/sample/search/search.go @@ -112,7 +112,7 @@ func Run(searchTerm string) {//一个string类型参数 go func() {//匿名函数 使用闭包访问waitGroup 和results变量 // Wait for everything to be processed. waitGroup.Wait()//递减计数 - + //直到调用了done方法 wait 就是回放 之后关闭通道 通道关闭 goroutine就不再工作 // Close the channel to signal to the Display //results 之前定义了 用关闭通道的方式 通知display函数 可以退出了 // function that we can exit the program. @@ -124,6 +124,7 @@ func Run(searchTerm string) {//一个string类型参数 // return after the final result is displayed. //调用match的display函数 Display(results) + //关闭通道 display也会返回 } // Register is called to register a matcher for use by the program. @@ -134,4 +135,7 @@ func Register(feedType string, matcher Matcher) { log.Println("Register", feedType, "matcher") matchers[feedType] = matcher + //将一个matcher值保存到注册匹配的映射中 + //会在main函数之前被完成。 + // } diff --git a/chapter3/READMe.md b/chapter3/READMe.md new file mode 100644 index 0000000..ca73c21 --- /dev/null +++ b/chapter3/READMe.md @@ -0,0 +1,98 @@ +# 打包和工具链 + +- 如何组织Go代码 +- 使用Go自带工具命令 +- 与其他开发者合作 + +## 包 + +设计理念是使用包来封装不同的语义单元功能,更好的复用代码。 + +- 包名 + + 包名及目录命名使用,简洁,清晰,全小写的名字 +- main包 + + 编译时会把包含main名字的包编译为二进制可执行文件。所有的Go语言编译的可执行程序必须有一个叫main的包 + main()函数是程序的入口,会使用main包代码所在目录目录名作为二进制可执行文件的文件名 +- 命令 command 指可执行的程序。包值语义上可以导入的功能单元 + +例子 编写$GOPATH/src/test/hello.go +里面的package 写的是main 生成一个二进制文件名字叫test + + ``` + package main + import "fmt" + func main() + fmt.Println("oooo") + ``` + +如果$GOPATH/src/test/hello.go +里面的package 写的是hello并且包含了func main() 是无效的,认为它是一个包不是命令 + +## 导入 + +- import关键字 + + 告诉编译器到磁盘的哪里去找要到包 + +- 一旦找到一个满足import 语句的包就是停止查找,先找安装Go的目录然后才找GOPATH变量里面的目录 +- 远程导入 + + 如果是url 工具链使用DVCS获取包。使用go get命令完成,go get将获取任意指定url的包 具有递归属性 扫描源码树 +- 命名导入 + + 重名的包使用命名导入 + + ``` + package main + import ( + "fmt" + myfmt "mylib/fmt" + ) + ``` +- 导入不需要引用这个包的标识符 + + 使用下划线 (_) 空白标识符 + +## 函数init + + 每个包可以包含任意个init函数并且都在执行开始时被被调用。 +都在main函数之前执行。 +main.go 使用postgres.go init函数及空白符使用 + +## 工具命令 + +- go run 先构建程序 然后执行 +- go build 先编译 然后执行 +- go vet 检查错误 +- go fmt 格式化代码 +- go doc 查看文档 go doc tar …… 展示tar命令 +- godoc -http=:6060启动web服务 +- 注释风格 /* */ // +- 函数的文档 + + 写直接写在声明之前// 如果是大段文字 可以在工程里 + 写一个叫做doc.go的文件 使用同样的包名 + 并把包的介绍使用注释/**/加载报名之前 + +## 与其他Go合作开发 + +- 包应该在代码库的根目录中 + + go get 指定了要导入的全部路径,意味着包名就是代码库的名字且包名应该位于代码库目录结构的根目录 +- 包可以非常小 +- 对代码指定 go fmt +- 写文档 + +## 依赖管理 + +- godep vender gopkg.in 工具 + +## 第三方依赖库 + +godep 和vender 第三方(verdoring)导入路径重写特性解决了依赖问题。 +思想是把所有的依赖包复制到工程代码目录里,然后使用工程内部的依赖包在所在目录来重写所有的导入路径 +- mod + +- gb 第三方代码 vendored code 工具链 有些不兼容 diff --git a/chapter3/dbdriver/main.go b/chapter3/dbdriver/main.go index 8772d3b..ee17f51 100755 --- a/chapter3/dbdriver/main.go +++ b/chapter3/dbdriver/main.go @@ -4,7 +4,7 @@ package main import ( "database/sql" - +//空白符 让init运行 还不会因为包未使用产生错误 _ "github.com/goinaction/code/chapter3/dbdriver/postgres" ) diff --git a/chapter3/dbdriver/postgres/postgres.go b/chapter3/dbdriver/postgres/postgres.go index 2ef5470..4535218 100755 --- a/chapter3/dbdriver/postgres/postgres.go +++ b/chapter3/dbdriver/postgres/postgres.go @@ -18,7 +18,7 @@ func (dr PostgresDriver) Open(string) (driver.Conn, error) { var d *PostgresDriver // init is called prior to main. -func init() { +func init() {//初始化函数 把数据注册到sql包里 d = new(PostgresDriver) sql.Register("postgres", d) } diff --git a/chapter4/README.md b/chapter4/README.md new file mode 100644 index 0000000..85aac7f --- /dev/null +++ b/chapter4/README.md @@ -0,0 +1,9 @@ +# 数组切片和映射 + +数组 切片 映射 管理集合处理数据 + +## 数组 + +是切片和映射的基本结构 + +- 内部实现 From c509fc55f0992b5d1b691d611a0fdcf72d38c883 Mon Sep 17 00:00:00 2001 From: chao Date: Sat, 23 Nov 2019 08:47:41 +0800 Subject: [PATCH 3/7] array slice --- chapter2/README.md | 1 + chapter4/README.md | 2 -- chapter4/arraycode/arrexp.go | 66 ++++++++++++++++++++++++++++++++++++ chapter4/main.go | 5 +++ chapter4/sliccode/slicexp.go | 58 +++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 chapter4/arraycode/arrexp.go create mode 100644 chapter4/main.go create mode 100644 chapter4/sliccode/slicexp.go diff --git a/chapter2/README.md b/chapter2/README.md index 3398d64..1af1430 100644 --- a/chapter2/README.md +++ b/chapter2/README.md @@ -19,6 +19,7 @@ 第二章介绍的的是一个rss 匹配程序内容,介绍从每个代码片段介绍语法规则及现象,介绍众多的使用方法和具体实例。 + ## 小结 - 每个代码文件都属于一个包,报名应该与代码文件所在文件夹同名 diff --git a/chapter4/README.md b/chapter4/README.md index 85aac7f..d96cb3f 100644 --- a/chapter4/README.md +++ b/chapter4/README.md @@ -5,5 +5,3 @@ ## 数组 是切片和映射的基本结构 - -- 内部实现 diff --git a/chapter4/arraycode/arrexp.go b/chapter4/arraycode/arrexp.go new file mode 100644 index 0000000..496343e --- /dev/null +++ b/chapter4/arraycode/arrexp.go @@ -0,0 +1,66 @@ +package arraycode + + +func init(){ + var array0 [5]int + fmt.Println(" var array0 [5]int 声明一个5个元素的int",array0) + array1 := [5]int{10,20,30,40,50} + fmt.Println(" array1 := [5]int{10,20,30,40,50} 声明一个5个元素的int",array1) + array3 := [...]int{11,21,31,41,51} + fmt.Println(" array3 := [...]int{11,21,31,41,51} 使用...代替数量 声明一个5个元素的int",array3) + array4 := [5]int{1:10, 2:20} + fmt.Println(" array4 := [5]int{1:10, 2:20} //声明一个有5个元素的数组 初始化1,2为索引的元素 其余是0 ") + for index,val :=range array4{ + fmt.Println("array4:index->",index,"-",val) + } + array0[1]=23 + fmt.Println("array0 使用【】访问索引操作array0[1]=23 ",array0) + var pointstring = "声明一个所有元素都是指针的数组。使用*运算符访问元素指针所指向的值\n" + array5 := [5]*int{0:new(int),1:new(int)} + var code5="array5 := [5]*int{0:new(int),1:new(int)}//声明包含5个元素的指整数的数组, + / 用整数型指针初始化索引为0 和1 的数组元素 *int 类型" + *array[0]=10 + *array[1]=20 + var code5_1=" *array[0]=10 *array[1]=20 初始化索引0 1 \n" + fmt.Println(pointstring,array5,code5,code5_1) + array1=array3 + fmt.Println("array1=array3 把array3赋值array1 两个必须长度类型一样 array1:",array1) + + + fmt.Println("把一个指针数组赋值给另一个") + var array6 [3]*string + array7 := [3]*string{new(string),new(string),new(string)} + *array7[0]="red" + *array7[1]="blue" + *array7[2]="green" + array6=array7 + //两个数组指向同一个字符串 + //如果改变 *array7[2] 那么*array6[2]的值也会改变 + var array8[4][2]int + array:=[4][2]int{{0,0},{1,1},{2,2},{3,3},{4,4}} + array:=[4][2]int{{0,0},{3,3},3:{4,4}} + //位置必须是一个对应一个 尤其是加了索引不可以越位 + //从前向后数数如果空就是0 + array:=[2][2]int{1:{0:3}} + //访问二维数组 + var array[2][2]int + array[0][0] =10 + array[0][1]=23 + array[1][0]=44 + + var array9 [2]int =array1[1] + var value int = array[0][1] + +} +var array [le6]int //8M的数组 +foo(array) +func foo(array [le6]int){ + fmt.Println(array) +}//每次传递都要在栈上分配8M的内存整个数组的值8m的内存在复制 + +var arrayle5[le6]int +foo6(&array) +func foo6(array *[le6]int){ + //传入地址 在栈上分配了8个字节的内存 + // +} \ No newline at end of file diff --git a/chapter4/main.go b/chapter4/main.go new file mode 100644 index 0000000..612c208 --- /dev/null +++ b/chapter4/main.go @@ -0,0 +1,5 @@ +package main + +import ( + "arraycode/arrexp" +) \ No newline at end of file diff --git a/chapter4/sliccode/slicexp.go b/chapter4/sliccode/slicexp.go new file mode 100644 index 0000000..494bc57 --- /dev/null +++ b/chapter4/sliccode/slicexp.go @@ -0,0 +1,58 @@ +package sliccode + +func init(){ + fmt.Println("长度和容量都是5个元素:slice :make([]string,5)") + slice :=make([]string,5) + slice :=make([]string,3,5) + fmt.Println("长度3 容量都是5个元素:slice :make([]string,3,5)") + + slice := []string{"red","blue","green","yellow","pink"} + //字符串切片 长度和容量都是5个 + + slice := []int{10,20,30}//整形切片 长度容量都是3 + + slice := []string{99:""}//初始化100个空字符串的元素 + //【】没有指定值创建的是数组 + array :=[3]int{2,3,4} + + //nil 切片 + var slice []int + //空切片 + slice :=make([]int,0) + slice:=[]int{} + //调用内部函数 append len cap +} + +func setValue(){ + slice := []int{01,32,43,44,44} + slice[1]=11111 + newSlice := slice[1:3]//只能看4个 + //底层数组【0:01,1:32,2:43,3:44,4:44】 5个 + //切片 后 是 从1个到第3个容量是4个 指针指向第一个 + //长度容量计算 + //容量是k 的切片 slice [i:j] + //长度 j-i + //容量 k-i + //第一个是表示新切片开始的元素索引位置 + //第二个表示开始的索引位置加上希望包含元素个数 结果索引+个数 + //两个切片共享了底层数组,一个改变另一个也改变 +} + +func updateValue(){ + slice :=[]int{10,20,30,40,50} + newSlice := slice[1:3] + newSlice[1]=999 + newSlice[3]=999//panic: runtime error: index out of range + + fmt.Println(slice) +} + +func appendValue(){ + fmt.Println("append",slice) + slice :=[]int{10,20,30,4,5} + newSlice:=slice[1:3] + newSlice =append(newSlice,50) + fmt.Println("appendlen:",cap(newSlice),"slice",slice,newSlice) + fmt.Println("增加容量") + +} \ No newline at end of file From cbebd5cb962c9da1364c8fe4ee50af9ba68ae5eb Mon Sep 17 00:00:00 2001 From: cc Date: Sat, 23 Nov 2019 08:54:42 +0800 Subject: [PATCH 4/7] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d7b0286..70b9b20 100755 --- a/README.md +++ b/README.md @@ -2,3 +2,4 @@ code ==== Source Code for Go In Action examples +练习及笔记 From aa85faed3a7834fd17ba19810ca156061b5e39b3 Mon Sep 17 00:00:00 2001 From: chao Date: Sat, 23 Nov 2019 16:27:59 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=95=B0=E7=BB=84=E5=88=87=E7=89=87=20?= =?UTF-8?q?=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter4/README.md | 8 ++++- chapter4/sliccode/mapexp.go | 61 ++++++++++++++++++++++++++++++++++++ chapter4/sliccode/slicexp.go | 59 +++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 chapter4/sliccode/mapexp.go diff --git a/chapter4/README.md b/chapter4/README.md index d96cb3f..1489a56 100644 --- a/chapter4/README.md +++ b/chapter4/README.md @@ -4,4 +4,10 @@ ## 数组 -是切片和映射的基本结构 +数组是切片和映射的基础,切片建立在底层的数组之上,映射使用散列 +切片使用时主要长度的容量,因为是共享底层数组所以最好使用 +相等长度容量之后使用append来扩容,操作时会创建一个新的数组 +不会对原有切片造成影响。 +映射长度容量没有限制 +len可以获得切片映射长度 +cap只能获取切片容量 diff --git a/chapter4/sliccode/mapexp.go b/chapter4/sliccode/mapexp.go new file mode 100644 index 0000000..5d22f35 --- /dev/null +++ b/chapter4/sliccode/mapexp.go @@ -0,0 +1,61 @@ +package sliccode + +//Map 映射是一种数据结构 用于存储一系列无序的键值对 +//映射基于键来存储值 基于键快速检索数据 +//映射是一个集合 映射是无序的集合 +//散列表 包含一组桶 +//操作时 都要选择一个桶 +// 操作映射时指定的键值传给映射的散列函数 散列函数生成一个索引 + +func init(){ + //创建一个 键是string 值是int的映射 + dict := make(map[string]int) + //键值都是string的映射 + dict :=map[string]string{} + //切片 函数 包含切结构的类型的类型 因为包含引用语义 + //不能作为映射的键 + //dict := map[[]string]int{} + //声明一个包含字符串切片的映射 + dict :=map[int][]string{} + + colors := map[string]string{} + colors["red"]="#da1337" + + //nil 映射 不能用来存储键值 会报错 + // var colors map[string]string + // colors["red"] ="da1228" + + +} + +func isSet(){ + vaule ,exists := colors["blue"] + if exists { + fmt.Println(value) + } + value := colors["blue"] + if value !=""{ + fmt.Println(value) + } +} + +func forLoop(){ + colors :=map[string]string{ + "AliceBule" : "#f0f8ff", + "Coral" : "#ff7F50", + "DarKray": "#a9a9a9", + "ForestGreen": "#23b22", + } + for key ,value := range colors{ + fmt.Printf("keys %s -value :%s\n",key,value) + } + delete(colors,"Coral") + removeColor(colors,"DarKary") + for key ,value := range colors{ + fmt.Printf("keys %s -value :%s\n",key,value) + } +} + +func removeColor(colors map[string]string, key string){ + delete(colors,key) +} diff --git a/chapter4/sliccode/slicexp.go b/chapter4/sliccode/slicexp.go index 494bc57..e78dd34 100644 --- a/chapter4/sliccode/slicexp.go +++ b/chapter4/sliccode/slicexp.go @@ -55,4 +55,61 @@ func appendValue(){ fmt.Println("appendlen:",cap(newSlice),"slice",slice,newSlice) fmt.Println("增加容量") -} \ No newline at end of file +} + +func threeSlice(){ +slice :=[]string{"Apple","Orange","Plum","Bannane","Grape"} +//长度为1个元素 容量为2个元素 +newSlice :=slice[2:3:4] +//slice [i:j:k] 第一个表示开始的索引位置, +//第二个表示索引位置加上元素的个数 1 结果是3 为了设置容量, +//从索引位置开始 加上希望容量包含的元素个2 结果是4 +//长度j-i +//容量k-i +//容量大于已有容量会报错 就是超过原来的容量 +fmt.Println(newSlice) +//panic: runtime error: slice bounds out of range +// f :=slice[2:3:6] +// fmt.Println(f) +} + +func sameLens(){ + source := []string{"Apple","Orange","Plum","Bannane","Grape"} + slice := source[2:3:3] + //长度和容量一样 + //现在长度和容量一致,还是共享着底层数组但是后面再进行append操作时创建新的数组 + slice=append(slice,"232332")//最佳字符串 + slice=append(slice,"333")//最佳字符串 + + s1 :=[]int{1,2} + s2 :=[]int{3,4} + fmt.Printf("%v\n",append(s1,s2...)) + for index, value := range slice{ + fmt.Printf("Index:%d value :%s\n",index,value) + } + for index ,value := range slice{ + fmt.Printf("value %s vlaue-addr%X elemAddr %X\n", + value,&value,&slice[index]) + //range 返回的是副本 不是原始值 value 地址不变 要使用index 的方式访问 + } + for _,val :=range s1{ + fmt.Printf("value%d:",$val) + } + + for index:=1;index Date: Sun, 24 Nov 2019 22:58:27 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=A0=87=E8=AE=B0=E7=AC=AC=E4=BA=94?= =?UTF-8?q?=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter5/listing11/listing11.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chapter5/listing11/listing11.go b/chapter5/listing11/listing11.go index a3698e5..a8a6463 100755 --- a/chapter5/listing11/listing11.go +++ b/chapter5/listing11/listing11.go @@ -7,17 +7,21 @@ import ( ) // user defines a user in the program. +//定义一个用户类型 type user struct { name string email string } // notify implements a method with a value receiver. +//使用值接受者实现一个方法 func (u user) notify() { fmt.Printf("Sending User Email To %s<%s>\n", u.name, u.email) } +//值接收者 +//指针接受者 // changeEmail implements a method with a pointer receiver. func (u *user) changeEmail(email string) { From 01dea3ca9b666682de5916b4b87dbc57a28249fb Mon Sep 17 00:00:00 2001 From: cc Date: Mon, 25 Nov 2019 19:56:16 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=20(#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter5/README.md | 244 ++++++++++++++++++++++++++++++++ chapter5/listing11/listing11.go | 8 +- chapter5/listing34/listing34.go | 2 + chapter5/listing35/listing35.go | 14 +- chapter5/listing36/listing36.go | 10 +- chapter5/listing50/listing50.go | 4 +- 6 files changed, 269 insertions(+), 13 deletions(-) create mode 100644 chapter5/README.md diff --git a/chapter5/README.md b/chapter5/README.md new file mode 100644 index 0000000..86ff18f --- /dev/null +++ b/chapter5/README.md @@ -0,0 +1,244 @@ +# 类型 + +## 声明 + + type 声明用户定义的类型 + 一个结构类型 + ``` + type user struct { + name string + ext int + privileged bool + } + //声明user 类型的变量 并初始化其为零值 + var bill user + //声明一个suer 类型的变量 + lisa := user { + name: "lisa, + ext : 1, + privileged: true + } + lisa := user {"lisa",1,true} + + type admin struct{ + persion user + level string + } + fred := admin { + person :user { + name : "lisa", + ext : 123, + privileged : true, + }, + level :"super", + } + type Duration int64 //使用的是内置in64 但是不能等同于他就是int64 + var dur Duration + dur = int64(1000)//报错 编译器不会做隐式转换 + ``` + +## 函数 + +关键字func 和函数名之间的参数被称为接收者 将函数与接收者的类型绑定在一起 +如果一个函数有接收者,这个函数被称为方法 + ``` + func (u user) notify() { + //func 和函数之间的参数 成为接收者 + fmt.Printf("Sending User Email To %s<%s>\n", + u.name, + u.email) + } + ``` +使用指针接收者 + ``` + func (u *user) changeEmail(email string) { + //指向user类型的指针 来调用notify方法 + u.email = email + } + 指针调用 notify方法 为了支持这种方法 go语言调整了指针的来符合接受者的定义 (*lisa).notify() + lisa := &user{"Lisa", "lisa@email.com"} + lisa.notify() + //值类型也可以调用指针接收者 + bill.changeEmail("bill@newdomain.com") + //(&bill),changeEmail(bill@newdomain.com) + bill 值得到一个指针,这个指针就能够匹配方法的接收者类型,在进行调用, + Go 即允许使用值,也允许使用指针来调用方法,不必严格符合接收者的类型 + ``` + +## 类型的本质 + + 如果给类型增加或者删除某个值,是要创建一个新的值,还是要更改当前的值 + - 如果要创建一个新值使用值接收者 + - 如果修改当前值使用指针接收者 + * 是按值传递还是按指针传递 + +### 内置类型 + + - 原始类型 的增加删除会创建一个新的值 + * 数值类型 + * 字符串类型 + * 布尔类型 + 把这些类型传递给方法函数时,传递一个对应的值的副本 + +字符串string 原始的数据值,在函数或方法传递时 传递字符串的副本 例内置 Trim 方法 + +### 引用类型 + + - 引用类型 创建变量时 创建的变量被称为标头 header的值 (从技术细节上说 字符串也算一种引用类型) + * 切片 + * 映射 + * 通道 + * 接口 + * 函数类型 + +每个引用类型创建的标头值是包含一个指向底层数据结构的指针。 +每个引用类型还包含一组独特的字段,用于管理底层的数据结构。 +因为标头是为赋值而设计的,所以永远不需要共享一个引用类型的值。 +标头值里包含一个指针,因此通过复制来传递一个引用类型的副本,本质上就是在共享底层数据结构。 + +### 结构类型 + +``` +type File struct{ + *file +} +//file 是*File的实际表示 +//额外的已成数据结构保证咩有哪个os的客户端能够覆盖这些数据 +//如果覆盖这些数据,可能在变量终结时关闭错误的文件描述符 +type file struct{ + fd int + name string + dirinfo *dirInfo //除了目录结构 此字段为nil + nepipe int32 //Write 操作时遇到连续EPIPE的次数 +} +``` +通过嵌套指针的方式阻止复制。 +``` +func Open(name sting)(file *File, err error){ + return OpenFile(name, O_RDONLY, 0) +} +``` +Opne 函数 调用者得到是是一个指向File类型的指针, *File +Open创建了File类型的值,并返回值的指针。 +- 如果一个创建用的工厂函数返回了一个指针,就表示这个被返回的值的本质是非原始的。 +- 即便函数或者方法没有直接改变原始的值的状态,依旧应该是攻心啊高的方式传递 +- 例外 让类型值符合某个接口的时候,即便类型的本质是非原始本质的,也可以选择使用接收者声明方法。 + +## 接口 + +- 多态 根据类型的具体实现采取不同的行为的 能力 + + 如果一个类型实现了某个接口,所有使用这个接口的方法,都可以支持这种类型的值。 + +### 实现 + + - 接口定义行为的类型。不由接口直接实现,通过方法由用户一的类型实现。 + +如果用户定义的类型实现了某个接口类型声明的一组方法,那么这个用户定义的类型的值就可以赋给这个接口类型的值。这个赋值会把定义的类型的值存入接口类型的值 + +对接口值的方法调用会执行接口值里存储的用户定义的类型的值对应方法。因为任何用户定义的类型都可以实现接口,所以接口值方法的调用自然是一种多态。 +用户定义的类型通常叫做实体。 + + ``` + var n notifier + n = user{"Bill"} + //实体复制后接口 + notifier 接口的值 iTable + iTabe的地址 -------------------->user的类型 + user的地址 ------>User [存储的值] 方法集 + + ``` +接口值是一个两个字段长度的数据结构[notifier 接口的值] ,iTabe的地址, +存储值的类型信息。iTable包含了已经存储的值的类型信息以及相关联的一组方法。 +第二个指向所有存储的指针。将类型信息和指针组合在一起。 + + ``` + var n notifier + n = &user{"Bill"} + notifier 接口的值 iTable + iTabe的地址 -------------------->*user的类型 + user的地址 ------>User [存储的值] 方法集 + ``` +类型信息会存储一个指向保存的类型的指针,而接口值第二个字依旧保存指向指向实体值的指针。 + +### 方法集 + + 方法集定义了一组关联到给定类型的值或者指针的方法。定义方法时候使用的接收者的类型决定了这个方法是关联到值,还是关联到指针,还是两个都关联 + +(t T) t是变量,T是类型 + ``` + values metherds receivers + ----------------------------------- + T (t T) + *T (t T) and (t *T) + ``` +T类型值方法集只包含值接收者声明的方法。而指向T类型的指针的方法既包含值接收者声明的方法,也包含指针接收者声明的方法。值角度看很复杂。 + +接收者角度 + ``` + metherds receivers values + ----------------------------------- + (t T) T and *T + (t *T) *T + ``` +- 如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。 +- 如果使用值接收者来实现一个接口,那么哪个类型的值和指针都能够实现对应的接口 +- 因为不能总能获取一个值的地址所以值的方法集值包括了使用值接收者实现的方法 + +### 多态 + + ``` + type notifier interface{ + notify + } + type user {} + type admin{} + func (a *admin) notify{}//使用指针接收者 + func (u *user) notify{} //各自实现了接口 + //多态函数 实现了notifiter 接口的值作为参数 + func sendNotification(n notifier){ n.notify() } + //任意一个实体类型都能实现该接口,函数指针可以真对任意实体来执行 + bill :=user{} + lisa :=admin{} + sendNotification(&bill)//可以同时执行user admin实现的行为 + sendNotification(&lisa) + ``` + +### 嵌入类型 + + 嵌入类型是将已有的类型直接声明在新的结构类型里。被嵌入的类型被称为新的外部类型的内部类型。 + +- 内部类型相关的标识符会被提升到外部类型上 +- 被提升的标识符像直接声明在外部类型里面的标识符一样,也是外部类型的一部分。 +- 外部类型组合了内部类型包含的所有属性,并且可以添加新的字段和方法 +- 外部类型也可以通过声明与内部类型标识符同名的标识符来覆盖内部标识符的字段或者方法 + + ``` + type notifter interface{ + notify() + } + type user {name string } + type admin { user level string } + func sendMian(n notifter){ notify} + func (u *user) notify(){} + ad:= admin { + user : user {name : "test"}, + level :"super", + } + ad.user.notify() + ad.notify() + sendMian(&ad) + ``` + + ad 变量外部类型是admin 嵌入了user 类型 。内部类型的提升,内部类型的接口会自动提升到外部类型。内部类型的实现,外部类型也同样实现了这个接口 + +- 如果外部也实现了方法,那么内部就不会提升 func (ad *admin)notify(){} + +### 公开或未公开的标识符 + + - 控制可见性 + * 小写开头的标识符 对外部不可见 + * 大写则公开 + +工厂函数命名为New是习惯 +创建一个未公开的类型的值,并将这个值返回给调用者 diff --git a/chapter5/listing11/listing11.go b/chapter5/listing11/listing11.go index a8a6463..616ec48 100755 --- a/chapter5/listing11/listing11.go +++ b/chapter5/listing11/listing11.go @@ -14,8 +14,9 @@ type user struct { } // notify implements a method with a value receiver. -//使用值接受者实现一个方法 +//使用 值 接受者实现一个方法 func (u user) notify() { + //func 和函数之间的参数 成为接收者 fmt.Printf("Sending User Email To %s<%s>\n", u.name, u.email) @@ -24,7 +25,9 @@ func (u user) notify() { //指针接受者 // changeEmail implements a method with a pointer receiver. +//指针 接收者 func (u *user) changeEmail(email string) { + //指向user类型的指针 来调用notify方法 u.email = email } @@ -43,7 +46,8 @@ func main() { // Values of type user can be used to call methods // declared with a pointer receiver. bill.changeEmail("bill@newdomain.com") - bill.notify() + //(&bill),changeEmail(bill@newdomain.com) + bill.notify()//根据方法的接收者来使用返回操作及定义返回值类型 // Pointers of type user can be used to call methods // declared with a pointer receiver. diff --git a/chapter5/listing34/listing34.go b/chapter5/listing34/listing34.go index 89af05b..ad18c8f 100755 --- a/chapter5/listing34/listing34.go +++ b/chapter5/listing34/listing34.go @@ -20,6 +20,8 @@ func init() { // main is the entry point for the application. func main() { // Get a response from the web server. + //Get 返回一个http response 类型指针包含一个Body的字段 + //Body是io。ReadCloser接口类型的值 r, err := http.Get(os.Args[1]) if err != nil { fmt.Println(err) diff --git a/chapter5/listing35/listing35.go b/chapter5/listing35/listing35.go index 5a7dc99..2d969d9 100755 --- a/chapter5/listing35/listing35.go +++ b/chapter5/listing35/listing35.go @@ -8,17 +8,19 @@ import ( "io" "os" ) - +//拼接字符串 // main is the entry point for the application. func main() { - var b bytes.Buffer + var b bytes.Buffer// bytes 包的buffer 类型b用于缓冲数据 // Write a string to the buffer. - b.Write([]byte("Hello")) + b.Write([]byte("Hello"))//write 方法写入 // Use Fprintf to concatenate a string to the Buffer. - fmt.Fprintf(&b, "World!") - + fmt.Fprintf(&b, "World!") //追加 接受io.write 类型 + //bytes.Buffer 类型指针实现了io.Writer接口 + //拼接字符串 // Write the content of the Buffer to stdout. - io.Copy(os.Stdout, &b) + io.Copy(os.Stdout, &b)//写到终端 } + diff --git a/chapter5/listing36/listing36.go b/chapter5/listing36/listing36.go index 9e7de47..f41b31e 100755 --- a/chapter5/listing36/listing36.go +++ b/chapter5/listing36/listing36.go @@ -8,7 +8,7 @@ import ( // notifier is an interface that defined notification // type behavior. type notifier interface { - notify() + notify()//行为 } // user defines a user in the program. @@ -29,12 +29,15 @@ func main() { // Create a value of type User and send a notification. u := user{"Bill", "bill@email.com"} - sendNotification(u) - + sendNotification(u)//u没有实现 使用 sendNotification(&u) + + //不能将 u 类型是user 作为 sendNotification的参数类型 + //user 类型咩有实现notifier // ./listing36.go:32: cannot use u (type user) as type // notifier in argument to sendNotification: // user does not implement notifier // (notify method has pointer receiver) + //notify方法使用指针接收者声明 } // sendNotification accepts values that implement the notifier @@ -42,3 +45,4 @@ func main() { func sendNotification(n notifier) { n.notify() } +//接收 notifier 接口类型的值 之后接口调用n.notify方法 diff --git a/chapter5/listing50/listing50.go b/chapter5/listing50/listing50.go index b814573..78b9937 100755 --- a/chapter5/listing50/listing50.go +++ b/chapter5/listing50/listing50.go @@ -22,7 +22,7 @@ func (u *user) notify() { // admin represents an admin user with privileges. type admin struct { - user // Embedded Type + user // Embedded Type 嵌入类型 level string } @@ -41,5 +41,5 @@ func main() { ad.user.notify() // The inner type's method is promoted. - ad.notify() + ad.notify() //提升了 }