《GO语言实战》——笔记

第一章 简介

  • goroutine
    goroutine很想线程,但是它占用的内存远少于线程,需要的代码
  • 通道
    channel是一种内置的数据结构,可以让用户在不同的goroutine之间同步发送具有类型的数据
  • Go语言类型系统
    Go语言提供了灵活的,邬吉成的类型系统,无需降低运行性能就能最大成都上复用代码。
Go使用组合(composition)设计模式,只需要简单的讲一个类型嵌入到另一个类型,就能复用所有的功能。
  • 内存管理
    Go也拥有垃圾回收机制。
第二章快速开始一个go程序 1.main函数保存在名为main的包里,如果不在main包里,构建工具就不会生成可执行的文件。
2.一个包定义一组编译过的代码,类似于命名空间。
import ( "log" "os" _ "github.com/goinaction/code/chapter2/sample/matchers" )

"_" 是为了让go语言对包做初始化,但是并不使用包里的标识符。为了让程序的可读性更强,go编译器不允许声明某个导入却不使用, 下划线是让编译器接收这种导入。
func init() { loc.SetOutput(os.Stdout) }

程序中每个代码文件里的init函数都会在main函数执行前调用。
标识符以大写字母开头,为公开。 如果以小写字母开头则是不公开。不能被其他包中对象引用。
make(map[string]string)

map是Go语言里的一个引用类型,需要使用make来构造。
feeds, err := RetrieveFeeds()

:= 简化变量声明运算符。 这个运算符和var声明的变量没有任何区别
restuls := make(chan *Result)

在 go语言中, channel, map和 slice 一样,也是引用类型。不过通道本身实现的是一组带类型的值,这组值用于在goroutine之间传递数据。通道内制同步机制,从而可以保证通信安全。
如果main函数返回,整个程序也就终止了,Go程序终止时,还会关闭所有之前启动而且还在运行 goroutine
for _, feed := range feeds { }

for range实现对切片迭代,range可以用于迭代数组,字符串,切片,映射和通道。使用for range时,会返回两个值,第一个值时迭代的元素在切片里元素的位置,第二个时元素值的一个副本。
下划线标识符时占位符, 占据保存range 返回的索引值变量的位置。
matcher, exists := matchers[feed.Type] if !exists { // business logic }

go func(param int) { // code }{x}

使用关键字go 启动一个goroutine,并对这个goroutine做并发调度
在go语言中, 所有的变量都以值的方式传递
Go语言支持闭包,
因为有闭包,函数可以直接访问那些没有作为参数的变量。匿名函数并没有拿到这些变量的而副本,而是直接访问外层函数作用域中声明的这些变量。
type Feed struct { Name string `json:"site"` URI string `json:"link"` Type string `json:"type"` }

"`"里面的部分被称作为标记。这个标记里描述了JSON解码的元数据。
defer file.Close()

defer关键字安排随后的函数调用在函数返回后才会执行。
func (dec *Decoder) Decode(v interface{}) error

Decode方法接受一个类型为interface{}的值作为参数。 这个类型在Go语言里很特殊,一般会配合reflect包里提供的反射功能一起使用。
type Matcher interface { Search(feed * Feed, searchTerm string) ([]*Result, error) }

声明一个接口
命名的时候,如果接口类型值包含一个方法,那么这个类型的名字以er结尾.
如果要让用户定义的类型实现一个接口,这个用户定义的类型要实现接口类型里面声明的所有方法。
func (m defaultMatcher) Search(feed *Feed, serachTerm string) ([]*Result, error) { return nil, nil }

Search方法于 defaultMatcher类型的值绑定在一起,意味着我们可以使用defaultMatcher类型的值或者指针来调用Search方法。
因为大部分方法在被调用后都需要维护接收者的值的状态,所以最佳实践是,将方法的接收者声明为指针。
与直接通过值或者指针调用方法不同,如果直接通过接口类型的值调用方法,规则有很大不同。
  • 使用指针作接收者声明方法,只能在接口类型的值是一个指针的时候被调用。
  • 使用值作为接受者声明方法,在接口类型的值为值或指针的时候豆科鱼i被调用。
第三章 打包和工具链
  • 同一个目录下,所有的.go文件必须同一个包名
  • main的包具有特殊的含义。Go语言的编译程序会试图把这种名字的包编译为二进制可执行文件。
import ( "fmt" "strings" )

  • 如果需要导入多个包,习惯上是将import语句包装在一个导入块中。
编译器会使用Go环境变量设置的路径,通过引入的相对路径来查找磁盘上的包。标准库中的包会在安装Go的位置找到。Go开发者创建的包会在GOPATH环境变狼指定的目录里查找。
GOPATH指定的这些目录就是开发者的个人工作空间。
一旦编译器找到一个满足import的语句的包,就会进一步停止查找。
go get 远程导入 获取任意指定的url的包
go vet 代码检查
go fmt 代码格式化
第四章 数组、切片和映射 数组
  • 声明
    var array [5]int array := [5]int{1,2,3,4,5}// 自动计算长度 array := [...]int{1,2,3,4,5

array := [5]*int{0: new(int), 1: new(int)} *array[0] = 10 *array[1] = 20

赋值数组指针值会复制指针的值,不会复制指针所指向的值。
array1 := [2]*string{new(string),new(string)} var array2 [2]*string*array1[0] = "Red" *array1[1] = "Blue" array2 = array1*array2[0] ="black"fmt.Println(*array1[0]) fmt.Println(*array2[0])

在函数间传递数组
【《GO语言实战》——笔记】在函数间传递变量是,总是以值的方式传递。
如果比那辆是一个数组,意味着整个数组,不管有多长,都会完整复制,并传递给函数。
使用指针会更有效的利用内存,性能也更好。
var array [1e6]intfoo(&array)

Q
goroutine实现原理? select 多路复用? init 函数的执行顺序 匿名函数的匿名函数可以访问最外层的变量吗?(闭包有层级限制吗?) interface {} ??

    推荐阅读