/ 读书笔记

Go语言圣经 学习笔记 第一章

前言

1、Go的起源

  • C语言
  • Pascal语言 Modula-2激发了包的概念
  • CSP Communicating Sequential processes

2、语言特性

  • Go语言面向对象机制与一般语言不同,没有类层次机构,仅仅通过组合(而不是继承)简单的对象来构建复杂的对象。

第一章 入门

1.Hello World

  • Go语言的代码通过包(package)组织,包类似于其它语言里的库( libraries)或者模块(modules)。一个包由位于单个目录下的一个或多个.go源代码文件组成,目录定义包的作用。每个源文件都以一条 package声明语句开始,表示该文件属于哪个包,紧跟着一系列导入( import)的包,之后是存储这个文件里的程序语句.
  • main 包比较特殊。它定义了一个独立可执行的程序,而不是一个库。在 main 里的main函数也很特殊,它是整个程序执行时的入口.
  • 缺少必要的包或++导入不需要的包++,程序都无法编译通过

2.命令行参数

  • 程序的命令行参数可从os包的Args变量获取;os包外部使用os.Args访问该变量
  • os.Args变量是一个字符串(string)的切片(slice),Go言里也采用左闭右开形式,即,区间包括第一个索引元素,不包括最后一个, 因为这样可以简化逻辑。( 译注:比如a = [1, 2, 3, 4, 5], a[0:3] = [1, 2, 3],不包含最后一个元素)
  • os.Args[0], 是命令本身的名字;其它的元素则是程序启动时传给它的参数
  • Go语言只有for循环这一种循环语句。for循环三个部分不需括号包围。大括号强制要求,左大括号必须和post语句在同一行.for循环有多种形式:

    其中的一种为:
    for initialization; condition; post {
    // zero or more statements
    }
    
    可以变化为:while
    // a traditional "while" loop
    for condition {
    // ...
    }
    
    无限循环:
    // a traditional infinite loop
    for {
    // ...
    }
    
    for 循环的另一种形式, 在某种数据类型的区间( range) 上遍历,如:
    for _, arg := range os.Args[1:] {
        s += sep + arg
        sep = " "
    }
    
    此处使用了空标识符(blank identifier),即_(下划线),原因是go语言不允许使用无用的局部变量
  • 声明一个变量有好几种方式,下面这些都等价:
    s := ""
    var s string
    var s = ""
    var s string = ""
    
    一种形式,是一条短变量声明,最简洁,但只能用在函数内
    部,而不能用于包变量。第二种形式依赖于字符串的默认初始化零值机制,被初始化为""。第三种形式用得很少,除非同时声明多个变量。第四种形式显式地标明变量的类型,当变量类型与初值类型相同时,类型冗余,但如果两者类型不同,变量类型就必须了.

3.查找重复的行

  • map存储了键/值( key/value) 的集合,对集合元素,提供常数时间的存、取或测试操作。键
    可以是任意类型,只要其值能用==运算符比较,最常见的例子是字符串;值则可以是任意类型,内置函数 make 创建空 map,例如:
    counts := make(map[string]int)
    
  • os.Open 函数返回两个值。第一个值是被打开的文件( *os.File ) os.Open 返回的第二个值是内置 error 类型的值。如果 err 等于内置值 nil ( 译注:相当于
    其它语言里的NULL)
  • map 是一个由 make 函数创建的数据结构的引用。 map 作为为参数传递给某函数时,该函数接收这个引用的一份拷贝( copy,或译为副本) ,被调用函数对map底层数据结构的任何修
    改,调用者函数都可以通过持有的map引用看到。在我们的例子中, countLines 函数向 counts 插入的值,也会被 main 函数看到。( 译注:类似于C++里的引用传递,实际上指
    针是另一个指针了,但内部存的值指向同一块内存)

4.GIF动画

  • gif.GIF是一个struct类型(类似于C语言中的结构体) 。struct是一组值或者叫字段的集合,不同的类型集合在一个struct可以让我们以一个统一的单元进行处理。anim是一个gif.GIF类型的struct变量。这种写法会生成一个struct变量,并且其内部变量LoopCount字段会被设置为nframes;而其它的字段会被设置为各自类型默认的零值。struct内部的变量可以以一个点(.)来进行访问,就像在最后两个赋值语句中显式地更新了anim这个struct的Delay和Image字段

5.获取URL

  • 引入net/http和io/ioutil包,http.Get函数是创建HTTP请求
    的函数,如果获取过程没有出错,那么会在resp这个结构体中得到访问的请求结果。resp.Body.Close关闭resp的Body流,防止资源泄露
    resp, err := http.Get(url)
    ...
    b, err := ioutil.ReadAll(resp.Body)
    resp.Body.Close()
    

6.并发获取多个URL

  • make函数创建了一个传递string类型参数的channel,用于goroutine之间进行参数传递:
    ch := make(chan string)
    
    当一个goroutine尝试在一个channel上做send或者receive操作时,这个goroutine会阻塞在调用处,直到另一个goroutine往这个channel里写入、或者接收值,这样两个goroutine才会继续执行channel操作之后的逻辑,往channel里发送一个值(ch<-experession),接收值(<-ch)
    ch <- fmt.Sprintf("while reading %s: %v", url, err)
    ....
    fmt.Println(<-ch) 
    

7.Web服务

  • 例子中有:
    func handler(w http.ResponseWriter, r *http.Request) {
    
    其中 *http.Request等同于c语言的指针,文章中并未进行说明,特此记录。
  • 服务器每一次接收请求处理时都会另起一个goroutine,这样服务器就可以同一时间处理多个请求,针对共享变量需要使用sync.Mutex进行锁定后更新
    var mu sync.Mutex
    var count int
    ...
    func handler(w http.ResponseWriter, r *http.Request) {
        mu.Lock()
        count++
        mu.Unlock()
        fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
    }
    

8.本章要点

  • switch多路选择说明:
    switch coinflip() {
        case "heads":
            heads++
        case "tails":
            tails++
        default:
        fmt.Println("landed on edge!")
    }
    
    Go语言并不需要显式地在每一个case后写break,语言默认执行完case后的逻辑语句会自动退出。如果你想要相邻的case都执行同一逻辑的话,需要自己显式地写上一个fallthrough语句来覆盖这种默认行为.

    Go语言里的switch还可以不带操作对象(译注:switch不带操作对象时默认用true值代替,然后将每个case的表达s式和true值进行比较);可以直接罗列多种条件,像其它语言里面的多个if else一样,这种形式叫做无tag switch(tagless switch);这和switch true是等价的
    func Signum(x int) int {
        switch {
            case x > 0:
                return +1
            default:
                return 0
            case x < 0:
                return -1
        }
    }
    
  • 命名类型:类型声明使得我们可以很方便地给一个特殊类型一个名字.例如:
    type Point struct {
        X, Y int
    } 
    var p Point
    
  • 指针:Go语言提供了指针,指针是可见的内存地址,&操作符可以返回一个变量的内存地址,并且*操作符可以获取指针指向的变量内容,但是在Go语言里没有指针运算,也就是不能像c语言里可以对指针进行加或减操作
  • 文档:你可以在 https://golang.org/pkghttps://godoc.org中找到标准库和社区写的packagegodoc这个工具可以让你直接在本地命令行阅读标准库的文档
  • 注释: 参考10.7.4