Go语言实战读书笔记

Go语言实战读书笔记,第1张

概述Go语言实战读书笔记 第二章 通道(channel)、映射(map)和切片(slice)是引用类型。引用类型的对象需要使用make函数进行构造。 在Go程序中,如果函数main()返回,整个程序就终止了。这时,Go会关闭全部goroutine。 使用for range迭代切片时,每次迭代前会返回两个值:元素在切片中的索引和元素副本。 Go支持闭包。 解析JSON示例: type Feed stru Go语言实战读书笔记 第二章

通道(channel)、映射(map)和切片(slice)是引用类型。引用类型的对象需要使用make函数进行构造。

在Go程序中,如果函数main()返回,整个程序就终止了。这时,Go会关闭全部goroutine。

使用for range迭代切片时,每次迭代前会返回两个值:元素在切片中的索引和元素副本。

Go支持闭包。

解析JsON示例:

type Feed struct {    name string `Json:"site"`    URI string `Json:"link"`    Type string `Json:"type"`}file,_ := os.Open(filename)var Feeds []*FeedJson.NewDecoder(file).Decode(&Feeds)

声明接口示例:

type Matcher interface {  Search(Feed *Feed,searchTerm string) ([]*Result,error)}

使用指针作为接受者声明的方法,只能由指针调用。使用值作为接受者声明的方法,值和指针都可以调用。当使用值调用时,传入方法的是值的副本。

如果使用for range对通道进行迭代时,当通道关闭后,迭代会终止。

除了main包外,Go包应当与其所在目录同名。

第三章

Go在寻找包时,先从$GOROOT目录下寻找,接着在$GOPATH目录下寻找。

命名导入:

import myfmt "mylib/fmt"import _ "mylib/init"

包的初始化。每个包可以包含多个init函数,这些函数将在main.main()之前执行。

Go工具

构建:

go build hello.go  # 构建指定文件。go build # 构建当前目录。go build github.com/goinaction/code/chapter3/wordcount # 构建指定包。go build github.com/goinaction/code/chapter3/... # 构建指定目录下的全部包。

清理构建文件:

go clean hello.go

构建并执行:

go run hello.go

检查代码中的常见错误:

go vetgo vet main.gogo vet .

格式化代码:

go fmtgofmt -l -w -s .

查看文档:

go doc targodoc -http=:6060
Go源代码文档

函数文档示例:

// RetrIEve 连接到配置库,收集各种链接设置、用户名和密码。这个函数成功时// 返回 config 结构,否则返回一个错误。func RetrIEve() (config,error) {    // ...}

包文档示例:

// 包 usb 提供了用于调用 USB 设备的类型和函数。package usb// ...
第四章

声明数组:

var a1 [5]intvar a2 = [3]int{1,2,3}var a3 = [...]int{1,3}var a4 = [3]*int{0: new(int),1: new(int)}

数组赋值会复制元素:

a1 := [3]string{"a","b","c"}var a2 [3]stringa2 = a1

多维数组:

var a1 [4][2]inta2 := [4][2]int{{10,11},{20,21},{30,31},{40,41}}a3 := [4][2]int{1: {0: 20},3: {1: 41}}var a4 [2]int = a3[1]

不要用数组作为函数参数。这么做会复制大量对象。要使用切片。

建立切片:

s1 := make([]int,5)s2 := make([]int,3,5)s3 := []{1,3}s4 := []string{99: ""}s5 := s1[1:3] # s5和s1共享同一个底层数组s6 := s1[2:3:4] # s6是长度为1,容量为2的切片

切片会包含一个底层数组。

切片和数组的区别在于,[]中没有数字。

对于底层数组容量是k的切片s[i:j],其长度是j-i,容量是k-i。

在对切片进行迭代时,返回的是切片元素的副本。每次迭代时,值副本的地址是相同的。

多维切片:

s := [][]int{{10},{100,200}}

切片包含地址指针、长度和容量。在64位计算机上,一个切片占用24字节。复制切片时不会复制底层数组,因此将切片作为参数传递给函数,开销很小。

切片函数:

cap(s) # 容量len(s) # 长度append(s,element)

映射使用了散列表。在每次迭代中,各元素返回的次序可能不同。

建立映射:

m1 := make(map[int]int)m2 := map[string]string{"Red": "#da1337","Orange": "#e95a22"}

映射的键必须是可以使用==比较的对象。函数、切片、以及包含切片的对象,由于具有引用语义,不能作为映射的键。

从映射中获取键对应的值时,如果键不存在,会返回零值。

映射函数:

delete(m,"key")
第五章

Go是静态类型语言。

自定义类型字面值:

type user struct {  name string  email string}type admin struct {  person user  level string}u1 := user{"lisa","lisa@abc.com"}u2 := user{name: "lisa",email: "lisa@abc.com"}a1 := admin{  person: user{"lisa","lisa@abc.com"}  level: "super"}

以指针为接收者的函数只能通过指针调用。以值为接收者的函数可以通过值或指针调用。对于以值为接收者的函数,函数域中的接收者是值的副本,即使通过指针调用时也是如此。

package mainimport (     "log")func main() {     u1 := user{"Tom"}     u2 := &user{"Jerry"}     u1.name()     u2.name()     log.Printf("%p %p",&u1,u2)}type user struct {     name string}func (r user) name() {     log.Printf("%s %p %p",r.name,&r,&r.name)}

如果函数需要修改接收者的状态,要以指针作为接收者。否则使用值作为接收者。

Go中的引用类型有:切片、映射、通道、接口和函数。

接口是用于定义行为的类型。如果一个类型实现了某个接口所声明的全部方法,这个类型的对象就可以赋值给做对应接口类型的变量。在赋值完成后, 会建立一个接口对象。接口对象包含两个指针:一个指向itable,一个指向存储的值。itable包含了存储值的类型信息,以及与这个值相关联的一组方法,称为方法集。方法集定义了接口的接收规则。

方法接收者
T (t T)
*T (t T) 和 (t*T)

嵌入类型:

type user struct {  name string  email string}func (r user) hello() string {  return "hello " + r.name}type admin struct {  user  level string}a := admin{}a.user.namea.namea.user.hello()a.hello()

被嵌入的类型也叫内部类型。内部类型中的标志符(成员和函数)会被提升到外部类型中。

以小写字母开头的标识符是包私有标识符,在包外不可见。对于未公开的内部类型,其公开成员可以通过标识符提升,以外部类型成员的方式访问。

第六章

Go使用的同步模型是通信顺序模型(Communicating Sequential Processes,CSP),各个goroutine通过传递消息通信,而非通过锁和共享内存来共享状态。

Go运行时会在逻辑处理器上调度goroutine。从1.5版本起,Go运行时会为每个物理处理器分配一个逻辑处理器(每个cpu一个还是每个核一个?)。当goroutine指定到一个阻塞的系统调用时,运行时将线程和goroutine从逻辑处理器上分离。被分离的线程会继续阻塞,等待系统调用返回。而逻辑处理器会建立一个新线程,从队列中选取一个goroutine,将新线程和goroutine绑定到逻辑处理器上。

在处理网络I/O时,goroutine会集成到网络轮询器的运行时。

Go运行时的线程数量默认为10000。超过这个数量时,运行时会崩溃。使用runtime/deBUG包中的方法SetMaxThreads()可以提高线程数量。

并发concurrency不是并行parallelism。并行是让不同的代码片段同时在不同的物理处理器上执行。并行指同时处理很多事情。并发指同时管理很多事情。

调用runtime包的方法GOMAXPROCS()可以设置Go运行时逻辑处理器数量。

next:  for i := 0; i < 10; i++ {    for j := 0; j < 10; j++ {      if cond {        continue next      }    }  }

runtime.Numcpu()返回物理处理器数量。

runtime.Gosched()从线程退出,并放回队列。

unbuffered := make(chan int) // 无缓冲区的通道buffered := make(chan int,10) // 有缓冲区的通道

无缓冲区通道要求发送方和接收方同时准备好。如果一方没有准备好,另一方会阻塞。

package mainimport (     "fmt")func main() {     input := make(chan int)     go func() {             input <- 1     }()     foo(input,10)}func foo(input chan int,end int) {     x := <-input     fmt.Println(x)     if x >= end {             return     }     go foo(input,end)     input <- x + 1}
第七章
import (  "os"  "os/signal")signalQueue := make(chan os.Signal)signal.Notify(signalQueue,os.Interrupt) # 接收信号for {  if interrupted() {    break  }  // ...}func interrupted() bool {   select {   case <-signalQueue:     signal.Stop(signalQueue) # 停止接收信号     return true   default:     return false   }}
a := []int{1,2}func add(arr ...int) {  b := append(a,arr...)}

判断超时和终端的示例:

interrupt := make(chan os.Signal,1)complete := make(chan error)timeout := time.After(3 * time.Second)signal.Notify(r.interrupt,os.Interrupt)go func() {  complete <- someFunc()}()select {case err := <-complete:  return errcase <-r.timeout:  return "timeout"}

每个调用signal.Notify(signalChan,signum)的队列,都会收到信号。

第八章
import "log"log.SetPrefix("TRACE: ")log.SetFlags(log.Ldata | log.Llongfile)// Ldate Ltime Llongfile Lmicroseconds Lshortfile// LstdFlags = Ldate | Ltimelog.Println("abc")log.Fatalln("abc")log.Panicln("abc")log.New(IoUtil.discard,"TRACE: ",log.LstdFlags|log.Lshortfile)log.New(io.MultiWriter(file,os.Stderr),"ERROR: ",log.LstdFlags|log.Lshortfile)

iota关键字为每个常量复制相同的表达式,并且每次自增1:

const (  a = 1 << iota // 1  b             // 2  c             // 4)const (  x = iota // 0  y        // 1  z        // 2)
第九章

单元测试示例:

import "testing"func TestFoo(t *testing.T) {  t.Log("abc")  t.Logf("a = %v",2)  t.Errorf("%v",123)  t.Fatal("abc")}

测试web服务示例:

import (  "testing"  "net/http"  "net/http/httptest")Feed := `<xml ...>`func MockServer() *httptest.Server {  return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r *http.Request) {    w.Writeheader(200)    w.header().Set("Content-Type","application/xml")    fmt.Fprintln(w,Feed)  }))}func TestFoo(t *testing.T) {  server := mockServer()  defer server.Close()  resp,err := http.Get(server.URL)  if err != nil {    t.Fatal(err)  }  defer resp.Body.Close()  // ...}

测试web服务示例:

http.HandleFunc("/some",func(rw http.ResponseWriter,r *http.Request) {  // ...})func TestSome(t *testing.T) {  req,_ := http.NewRequest("GET","/some",nil)  rw := httptest.NewRecorder()  http.DefaultServeMux.Servehttp(rw,req)}

基准测试:

func BenchmarkSprintf(b *testing.B) {  number := 10  b.resetTimer()  for i := 0; i < b.N; i++ {    fmt.Sprintf("%d",number)  }}
修订记录 2017年08月02日 建立文档。 2017年08月05日 增加笔记。 2017年08月07日 修正拼写错误。 总结

以上是内存溢出为你收集整理的Go语言实战读书笔记全部内容,希望文章能够帮你解决Go语言实战读书笔记所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1275618.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-09
下一篇2022-06-09

发表评论

登录后才能评论

评论列表(0条)

    保存