第一章

1、Go是一门编译型语言,Go语言的工具链将源代码及其依赖转换成计算机的机器指令(译注:静态编译)。Go语言提供的工具都通过一个单独的命令go调用,go命令有一系列子命令。最简单的一个子命令就是run。这个命令编译一个或多个以.go结尾的源文件,链接库文件,并运行最终生成的可执行文件。

2、Go语言原生支持Unicode,它可以处理全世界任何语言的文本。

3、如果不只是一次性实验,你肯定希望能够编译这个程序,保存编译结果以备将来之用。可以用build子命令:

$ go build helloworld.go

这个命令生成一个名为helloworld的可执行的二进制文件(译注:Windows系统下生成的可执行文件是helloworld.exe,增加了.exe后缀名),之后你可以随时运行它(译注:在Windows系统下在命令行直接输入helloworld.exe命令运行),不需任何处理(译注:因为静态编译,所以不用担心在系统库更新的时候冲突)

4、Go语言的代码通过包(package)组织,包类似于其它语言里的库(libraries)或者模块(modules)。一个包由位于单个目录下的一个或多个.go源代码文件组成, 目录定义包的作用。

5、Go中main包比较特殊,它定义了一个独立可执行的程序,而不是一个库。在main里的main 函数 也很特殊,它是整个程序执行时的入口

6、命令行参数

os包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从os包的Args变量获取;os包外部使用os.Args访问该变量。os.Args变量是一个字符串的切片,把切片s当做数组元素序列,序列的长度动态变化,用s[i]访问单个元素,用s[m:n]获取子序列,序列的元素数目为len(s)

os.Args的第一个元素,os.Args[0],是命令本身的名字;其它的元素则是程序启动时传给它的参数。

7、echo命令:把它的命令行参数打印成一行

 

//UNIX echo命令的实现
package main

import (
    "fmt"
    "os"
)

func main() {
    var s, sep string
    for i := 1; i<len(os.Args); I++ {
        s += sep + os.Args[I]
        sep = " "
    }
    fmt.Println(s)
}

8、Go语言中只有for循环,for循环的格式有两种,for和for range,for range类似python中的enumerate,在Go中因为不允许有无用变量,因此在for range语句中常会用到_来隐式地索引

9、声明方式

s := ""-->短变量声明,只能用在函数内部,不能用于包变量

var s string-->依赖于字符串的默认初始化零值机制,被初始化为""

10、+=连接原字符串、空格和下个参数,产生新字符串,并把它赋值给s。s原来的内容已经不再使用,将在适当时机对它进行垃圾回收

如果连接涉及的数据量很大,一种简单且高效的解决方案是使用strings包的Join函数

func main() {
    fmt.Println(strings.Join(os.Args[1:], " "))
}

 11、找出重复行

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    counts := make(map[string]int)
    input := bufio.NewScanner(os.Stdin) //新建一个bufio.Scanner类型input变量
    for input.Scan() { //扫描器从程序的标准输入进行读取,每一次调用input.Scan()读取下一行,并且将结尾的换行符去掉
//通过input.Text()来获取读到的内容。Scan函数在读到新行的时候返回true,在没有更多内容的时候返回false counts[input.Text()]
++ //相当于 line:=input.Text() counts[line] = counts[line] + 1 //键在map中不存在时也是没有问题的,当一个新的行第一次出现时,右边的表达式counts[line]根据值类型被推演为零值,int的零值是0 } for line, n := range counts { if n > 1{ fmt.Printf("%d\t%s\n", n, line) } } }

12、bufio包

使用该包可以简便和高效地处理输入和输出。其中一个最有用的特性是扫描器(Scanner)类型,它可以读取输入,以行或者单词为单位断开,这是处理以行为单位的输入内容的最简单方式

13、

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    counts := make(map[string]int)
    input := bufio.NewScanner(os.Stdin)
    for input.Scan() {
        counts[input.Text()]++  //相当于 line:=input.Text()  counts[line] = counts[line] + 1
        //键在map中不存在时也是没有问题的,当一个新的行第一次出现时,右边的表达式counts[line]根据值类型被推演为零值,int的零值是0
    }

    for line, n := range counts {
        if n > 1{
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

 

package main

import (
    "bufio"
    "fmt"
    "os"
)

//dup2打印输入中多次出现的行的个数和文本
//它从stdin或指定的文件列表读取

func main() {
    counts := make(map[string]int)
    files := os.Args[1:]
    if len(files) == 0{
        countLines(os.Stdin, counts)    
    } else {
        for _, arg := range files {
            f, err := os.Open(arg)
            if err != nil {
                fmt.Fprintf(os.Stderr, "dup2:%v\n", err)
                continue
            } 
            countLines(f, counts)
            f.Close()
        }
    }
    for line, n := range counts{
        if n > 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

func countLines(f *os.File, counts map[string]int) {
    input := bufio.NewScanner(f)
    for input.Scan() {
        counts[input.Text()]++
    }
}

 

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

func main() {
    counts := make(map[string]int)
    for _, filename := range os.Args[1:] {
        //ReadFile函数返回一个可以转化成字符串的字节slice
        data, err := ioutil.ReadFile(filename)
        if err != nil {
            fmt.Fprintf(os.Stderr, "dup3:%v\n", err)
            continue
        }
        for _, line := range strings.Split(string(data), "\n"){
            counts[line]++
        }
    }
    for line, n := range counts {
        if n > 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

 

14、GIF动画

15、获取一个URL

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
)

func main() {
    for _, url := range os.Args[1:] {
        resp, err := http.Get(url) //产生一个HTTP请求,如果没有出错,返回结果存在响应结构resp里面
        //resp的Body域包含服务器端响应的一个可读取数据流
        if err != nil {
            fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
            os.Exit(1)
        }
        //ioutil.ReadAll读取整个响应结果并存入b
        b, err := ioutil.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil {
            fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
            os.Exit(1)
        }
        fmt.Printf("%s", b)
    }
}
$ go build fetch.go
$ ./fetch http://gopl.io

16、并发获取多个URL

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "os"
    "time"
)

//和fetch一样获取URL的内容,但是它并发获取很多URL内容,这个进程使用的时间不超过耗时最长时间的获取任务
func main() {
    start := time.Now()
    ch := make(chan string)
    for _, url := range os.Args[1:]{
        go fetch(url, ch)  //启动一个goroutine
    }
    for range os.Args[1:] {
        fmt.Println(<-ch) //从通道ch接收
    }
    fmt.Printf("%.2fs elapsed\n", time.Since(start).Seconds())
}

func fetch(url string, ch chan <- string){
    start := time.Now()
    resp, err := http.Get(url)
    if err != nil {
        ch <- fmt.Sprint(err) //发送到通道ch
        return
    }

    nbytes, err := io.Copy(ioutil.Discard, resp.Body)
    resp.Body.Close() //不要泄露资源
    if err != nil {
        ch <- fmt.Sprintf("while reading %s: %v", url, err)
        return
    }
    secs := time.Since(start).Seconds()
    ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
}
$ go build fetchal.go
$ ./fetchall https://golang.org http://gopl.io https://godoc.org

goroutine是一个并发执行的函数。通道是一种允许某一例程向另一个例程传递指定类型的值的通信机制

17、一个Web服务器

 

posted @ 2020-06-03 15:35  LinBupt  阅读(136)  评论(0编辑  收藏  举报