读《Go语言圣经》记录(一)

读《Go语言圣经》记录(一)

在编程语言的海洋中,Go语言以其简洁的语法、高效的并发处理能力和强大的标准库迅速崭露头角,成为开发者的宠儿。本文将带大家深入探索《Go语言圣经》的入门章节,并结合实际示例和扩展知识,开启一段精彩的Go语言学习之旅。

第一章:入门

1.1 Hello, World

每个编程之旅都从"Hello, World"开始。在Go语言中,编写一个简单的"Hello, World"程序易如反掌。以下是代码示例:

go 复制代码
package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}

这段代码展示了Go语言的基本结构:package main声明了程序的入口包,import "fmt"引入了格式化I/O包,func main()是程序的入口函数,而fmt.Println则用于输出文本。运行这段代码,你将在控制台看到"Hello, 世界"的友好问候。

1.2 命令行参数

Go语言通过os包提供对命令行参数的访问。以下是一个示例,展示如何读取并处理命令行参数:

go 复制代码
package main

import (
    "fmt"
    "os"
)

func main() {
    args := os.Args
    for i, arg := range args {
        fmt.Printf("Argument %d: %s\n", i, arg)
    }
}

将此代码保存为args.go,然后通过命令行运行go run args.go arg1 arg2,你将看到程序输出传递给它的参数。

1.3 查找重复的行

处理文本数据是编程中的常见任务。下面是一个程序,用于查找输入中的重复行:

go 复制代码
package main

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

func main() {
    counts := make(map[string]int)
    input := bufio.NewScanner(os.Stdin)
    for input.Scan() {
        line := input.Text()
        counts[line]++
    }
    for line, count := range counts {
        if count > 1 {
            fmt.Printf("%d\t%s\n", count, line)
        }
    }
}

将此代码保存为dups.go,然后通过管道传递文本文件内容,如cat file.txt | go run dups.go,程序将输出文件中重复的行及其出现次数。

1.4 GIF动画

Go的imagegif包使得创建图像和动画变得简单。以下是一个生成GIF动画的示例:

go 复制代码
package main

import (
    "image"
    "image/color"
    "image/gif"
    "math"
    "os"
)

func main() {
    const (
        cycles  = 5
        res     = 0.001
        size    = 100
        nframes = 64
        delay   = 8
    )
    anim := gif.GIF{LoopCount: nframes}
    palette := []color.Color{color.White, color.Black}
    for i := 0; i < nframes; i++ {
        rect := image.Rect(0, 0, 2*size+1, 2*size+1)
        img := image.NewPaletted(rect, palette)
        for t := 0.0; t < cycles*2*math.Pi; t += res {
            x := math.Sin(t)
            y := math.Sin(t*1.5)
            img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), 1)
        }
        anim.Delay = append(anim.Delay, delay)
        anim.Image = append(anim.Image, img)
    }
    gif.EncodeAll(os.Stdout, &anim)
}

运行此程序并将输出重定向到GIF文件,如go run lissajous.go > out.gif,你将得到一个美丽的GIF动画。

1.5 获取URL

Go的net/http包提供了强大的HTTP客户端功能。以下是如何获取网页内容的示例:

go 复制代码
package main

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

func main() {
    resp, err := http.Get("https://example.com")
    if err != nil {
        fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
        os.Exit(1)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", resp.Request.URL, err)
        os.Exit(1)
    }
    fmt.Printf("%s", body)
}

将此代码保存为fetch.go并运行go run fetch.go https://example.com,你将在控制台看到网页的HTML内容。

1.6 并发获取多个URL

Go的并发模型是其最大的亮点之一。通过goroutines和channels,可以轻松地并发获取多个URL:

go 复制代码
package main

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

func main() {
    start := time.Now()
    ch := make(chan string)
    for _, url := range os.Args[1:] {
        go fetch(url, ch)
    }
    for range os.Args[1:] {
        fmt.Println(<-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.Sprintf("error: fetching %s: %v", url, err)
        return
    }
    defer resp.Body.Close()
    nbytes, err := io.Copy(io.Discard, resp.Body)
    if err != nil {
        ch <- fmt.Sprintf("error: reading %s: %v", url, err)
        return
    }
    secs := time.Since(start).Seconds()
    ch <- fmt.Sprintf("%.2fs  %7d  %s", secs, nbytes, url)
}

运行此程序并传递多个URL作为参数,你将看到每个URL的获取时间和数据大小。

1.7 Web服务

创建一个简单的Web服务器来响应HTTP请求:

go 复制代码
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe("localhost:8000", nil)
}

运行此程序并在浏览器中访问http://localhost:8000,你将看到请求的URL路径。

1.8 本章要点

本章涵盖了Go语言的基础知识,包括如何编写和运行程序、处理命令行参数、文本处理、图像生成、网络编程和并发编程。通过这些示例,我们不仅学习了Go语言的语法,还了解了其强大的标准库和并发模型。

扩展知识与最佳实践

错误处理

在处理外部操作(如文件I/O或网络请求)时,总是检查错误并进行适当的处理:

go 复制代码
resp, err := http.Get(url)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

使用defer确保资源被正确释放。

并发模式

Go的并发模型基于CSP(Communicating Sequential Processes)。使用goroutineschannels来协调并发任务:

go 复制代码
ch := make(chan int)
go func() {
    for i := 0; i < 3; i++ {
        ch <- i
    }
    close(ch)
}()
for num := range ch {
    fmt.Println(num)
}

性能优化

使用sync.Pool来重用对象,减少内存分配和垃圾回收的开销:

go 复制代码
var pool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 1024)
    },
}

func getBuffer() []byte {
    return pool.Get().([]byte)
}

func putBuffer(b []byte) {
    pool.Put(b)
}
相关推荐
clever10113 小时前
在QtCreator 4.10.2中调试qt程序qDebug()输出中文为乱码问题的解决
开发语言·qt
测试开发Kevin14 小时前
小tip:换行符CRLF 和 LF 的区别以及二者在实际项目中的影响
java·开发语言·python
松☆14 小时前
Dart 核心语法精讲:从空安全到流程控制(3)
android·java·开发语言
编码者卢布14 小时前
【Azure Storage Account】Azure Table Storage 跨区批量迁移方案
后端·python·flask
编码者卢布14 小时前
【App Service】Java应用上传文件功能部署在App Service Windows上报错 413 Payload Too Large
java·开发语言·windows
kaikaile199515 小时前
结构风荷载理论与Matlab计算
开发语言·matlab
切糕师学AI15 小时前
ARM 汇编器中的伪指令(Assembler Directives)
开发语言·arm开发·c#
吕司15 小时前
Qt的信号与槽
开发语言·qt
bjxiaxueliang16 小时前
一文掌握C/C++命名规范:风格、规则与实践详解
c语言·开发语言·c++
玄〤16 小时前
Java 大数据量输入输出优化方案详解:从 Scanner 到手写快读(含漫画解析)
java·开发语言·笔记·算法