1.1 Hello World

gopl_hello.go

package mainimport ("fmt"
)func main() {fmt.Println("Hello world!")
}

运行: go run gopl_hello.go
编译:go build gopl_hello.go
代码格式化工具: gofmt
自动添加或删除import 声明:goimports

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

1.2 命令行参数

os
获取外部变量 os.Args 是一个字符串的切片 对标python中的 sys.args有python经验真的很容易理解。

先看 python 例子实现:py_echo1.py

import sys
print(" ".join(sys.argv[1:]))

echo go语言示例1:gopl_echo1.go

// 实现 linux echo 字符串回显功能,回显输入的值。
package mainimport ("fmt""os"
)func main() {var s, sep stringfor i := 1; i < len(os.Args); i++ {s += sep + os.Args[i]sep = " "}fmt.Println(s)
}
  • 注释 \\

  • 声明变量 var, 若没有显式初始化,则赋予零值,数值类型是0, 字符串类型是空字符串。

  • 字符串连接符 +

  • 赋值运算符 +=

  • 短变量声明(short variable declaration) := (这不就是python中的海象运算符(赋值表达式 Assignment Expressions)嘛!语义也也一样!) 可省略 var 声明。

  • 循环语句 for
    go 语言只有for 这一种循环语句(python等语言 还有 while)

    for initialization; condition; post {// zero or more statements
    }
    

    initialization 可选,必须是简单语句(短变量声明,自增语句,赋值语句或函数调用)
    condition 可选, 是个布尔表达式(boolean expression), 在每次循环迭代开始时计算。true 即执行循环体。
    post 可选, 在循环体执行结束后执行,之后再次对 condition 求值,为false时循环结束。
    典型情况:

    // "while" loop 仅保留 condition
    for condition {// ...
    }
    
     // infinite loop  可用 break 或 return 语句终止循环for {// ...}
    

第二种实现方式,还是先看 python 例子实现:py_echo2.py

import sys
print(" ".join(w for _, w in enumerate(sys.argv[1:]))) # 还是 py_echo1.py 更简洁

echo go语言示例2:gopl_echo2.go

// 实现 linux echo 字符串回显功能,回显输入的值。
package mainimport ("fmt""os"
)func main() {s, sep:= "", " " for _, arg:= range os.Args[1:] {s += sep + arg}fmt.Println(s)
}
  • 产生一对索引和该索引的元素值 range 对标python中的 enumerate, 语言是互通的,有python经验真的很容易理解。
  • Go语言不允许使用无用的局部变量(local variables)
  • 空标识符(blank identifier)_ (下划线),空标识符可用于任何语法需要变量名但程序逻辑不需要的时候,丢弃不需要
    的循环索引, 保留元素值。
  • 声明变量的4种方式, 一般使用前两种形式。 ,初始值重要的话就显式地指定变量的类型,否则使用隐式初始化。
    s := ""                   // 短变量声明,最简洁,但只能用在函数内部,而不能用于包变量。
    var s string              // 依赖于字符串的默认初始化零值机制,被初始化为""。
    var s = ""
    var s string = ""        // 显式地标明变量的类型,当变量类型与初值类型相同时,类型冗余。
    

echo go语言示例3:gopl_echo3.go

package mainimport ("fmt""os""strings"
)func main() {fmt.Println(strings.Join(os.Args[1:], " "))
}
  • 效率更高的字符串连接方式 strings.Join(string_slice,"")

练习 1.1:

修改echo程序, 使其能够打印 os.Args[0] , 即被执行命令本身的名字。
gopl_echo_ex1_0.go

package mainimport ("fmt""os"
)func main() {fmt.Println(os.Args[0])
}

直接这样写输出的其实并不满足要求,会把执行程序一起打印./gopl_echo_ex1_0.go
以下做了改进,使用Split 分割了执行命令。
PS: 嘿嘿, golang Split切片取最后一值与python不同,不支持 [-1]呦!

gopl_echo_ex1.go

package mainimport ("fmt""os""strings"
)func main() {sp := strings.Split(os.Args[0], "/")value := sp[len(sp)-1]fmt.Println(value)
}

构建 go build gopl_echo_ex1.go
运行 ./gopl_echo_ex1 a b c d
输出 gopl_echo_ex1

练习 1.2:

修改echo程序, 使其能够打印 每个参数的索引和值,每个一行。
gopl_echo_ex2.go

package mainimport ("fmt""os""strings"
)func main() {for index, value := range os.Args {if index != 0 {fmt.Println(index, value)} else {sp := strings.Split(value, "/")value := sp[len(sp)-1]fmt.Println(index, value)}}
}

构建 go build gopl_echo_ex2.go
运行 ./gopl_echo_ex2 a b c d
输出

0 gopl_echo_ex2
1 a
2 b
3 c
4 d

练习 1.3:

了解1.6节 time包,11.4节标准测试程序,以得到系统性的性能评测。

// TODO 待补充

1.3 查找重复的行

dup go语言示例1:gopl_dup1.go

package mainimport ("bufio""fmt""os"
)func main() {counts := make(map[string]int)input := bufio.NewScanner(os.Stdin)for input.Scan() {counts[input.Text()]++}for line, n := range counts {if n > 1 {fmt.Println(n, line)}}
}

gopl_dup1.txt

Hello World!
666
Spaceack
SpaceackSpaceack
Hello World!
Spaceack
888
Hello World!
666

需要用重定向符<这样运行:go run gopl_dup1.go < gopl_dup1.txt。结果如下:

3 Hello World!
2 666
4 Spaceack
2

可以看到,两个空白行也被记录。

  • map 类似 python 的 dict, 存储(k-v)的集合。 常数时间存,取操作。
  • make 内置函数创建空map
  • map 迭代的顺序随机
  • bufio包用来处理输入输出,Scanner类型读取输入并将其拆成行或单词。
  • 每次调用input.Scan(),读入下一行并移除末尾换行符。
  • input.Text() 读取内容
  • tmp.Printf 参数格式转换字符(conversion character)
    %d 十进制整数
    %x, %o, %b 十六进制,八进制,二进制整数。
    %f, %g, %e 浮点数: 3.141593 3.141592653589793 3.141593e+00
    %t 布尔:true或false
    %c 字符(rune) (Unicode码点)
    %s 字符串
    %q 带双引号的字符串"abc"或带单引号的字符'c'
    %v 变量的自然形式(natural format)
    %T 变量的类型
    %% 字面上的百分号标志(无操作数)
    

dup go语言示例2:gopl_dup2.go

package mainimport ("bufio""fmt""os"
)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.Fprint(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()]++}
}

直接运行:go run gopl_dup2.go gopl_dup1.txt。结果如下:

4       Spaceack
2
3       Hello World!
2       666
  • os.Open 函数反回两个值。第个是被打开的文件(*os.File),其后被Scanner读取。第二个值是内置error 类型的值。如果err等于内置值nil,那么文件被成功打开。读取文件,直到文件结束。然后用close 关闭该文件,并释放占用的资源。
  • countLines 函数在声明前被调用。函数和包级别的变量(package-level entities)可以任意声明顺序,不影响被调用。

dup go语言示例3:gopl_dup3.go

package mainimport ("fmt""io/ioutil""os""strings"
)func main() {counts := make(map[string]int)for _, filename := range os.Args[1:] {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)}}
}

直接运行: go run gopl_dup3.go gopl_dup1.txt。结果如下:

3
3       Hello World!
2       666
4       Spaceack
  • ReadFIle 函数返回一个字节切片(byte slice),需要转换为string 才能使用strings.Split分割。
  • bufio.Scanner, ioutil.ReadFile, ioutil.WriteFIle都使用*os.FIleReadwrite方法。使用高级函数会更容易。

练习 1.4:

修改dup2程序, 出现重复的行时打印文件名称。
gopl_dup2_ex1.go

1.4 GIF动画

利萨如(Lissajous figures)图形:协振子在两个纬度上振动所产生的曲线。
Lissajous go语言示例1:gopl_lissajous.go

go build gopl_lissajous.go
./gopl_lissajous > lissajous_1,gif
// Lissajous generates GIF animations of random Lissajous figures.
package mainimport ("image""image/color""image/gif""io""math""math/rand""os""time"
)var palette = []color.Color{color.White, color.Black}const (whiteIndex = 0 // first color in paletteblackIndex = 1 // next color in palette
)func main() {// The sequence of images is deterministic unless we seed// the pseudo-random number generator using the current time.// Thanks to Randall McPherson for pointing out the omission.rand.Seed(time.Now().UTC().UnixNano())lissajous(os.Stdout)
}
func lissajous(out io.Writer) {const (cycles = 5res    = 0.001 // angular resolution// number of complete x oscillator revolutionssize = 100// image canvas covers [-size..+size]nframes = 64 // number of animation framesdelay   = 8  // delay between frames in 10ms units)freq := rand.Float64() * 3.0 // relative frequency of y oscillatoranim := gif.GIF{LoopCount: nframes}phase := 0.0 // phase differencefor 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*freq + phase)img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),blackIndex)}phase += 0.1anim.Delay = append(anim.Delay, delay)anim.Image = append(anim.Image, img)}gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}
  • 复合声明 []color.Color{...}gif.GIF{...}是实例化Go语言里的复合类型的一种写法。分别生成slice 切片和 struct结构体。
  • anim是一个gif.GIF类型的struct变量。
  • 其内部变量LoopCount字段会被设置为nframes,其它的字段会被设置为各自类型默认的零值。
  • struct内部的变量可以以一个点(.)来进行访问。
  • 外层循环会循环64次,每一次都会生成一个单独的动画帧。生成了一个包含两种颜色的201*201大小的图片,白色和黑色。所有像素点都会被默认设置为其零值。将结果append到anim中的帧列表末尾,并设置一个默认的80ms的延迟值。循环结束后所有的延迟值被编码进了GIF图片中,并将结果写入到输出流。
  • 内层循环设置两个偏振值。x轴偏振使用sin函数。y轴偏振也是正弦波,但其相对x轴的偏振是一个0-3的随机值,初始偏振值是一个零值,随着动画的每一帧逐渐增加。循环会一直跑到x轴完成五次完整的循环。每一步它都会调用SetColorIndex来为(x, y)点来染黑色。

练习 1.5:

修改前面的Lissajous程序里的调色板,由黑色改为绿色。
我们可以用color.RGBA{0xRR, 0xGG, 0xBB, 0xff}来得到#RRGGBB这个色值,三个十六进制的字符串分别代表红、绿、蓝像素。

var palette = []color.Color{color.RGBA(color.RGBA{0xAA, 0xCC, 0xBB, 0xff})}

练习 1.6:

修改Lissajous程序,修改其调色板来生成更丰富的颜色,然后修改SetColorIndex的第三个参数,看看显示结果吧。

var palette = []color.Color{color.RGBA(color.RGBA{0x11, 0xDD, 0xBB, 0xDD}), color.RGBA(color.RGBA{0xFF, 0xCC, 0x33, 0x55})}

1.5. 获取URL

gopl_fetch1.go

// Fetch prints the content found at a URL.
package mainimport ("fmt""io/ioutil""net/http""os"
)func main() {for _, url := range os.Args[1:] {resp, err := http.Get(url)if err != nil {fmt.Fprintf(os.Stderr, "fetch: %v\n", err)os.Exit(1)}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)}
}
  • net/http包, http.Get创建HTTP请求。
  • resp 的 Body字段包括一个可读的服务器响应流。ioutil.ReadAll函数从response中读取到全部内容;
  • resp.Body.Close关闭resp的Body流,防止资源泄露。
  • 无论哪种失败原因,我们的程序都用了os.Exit函数来终止进程,并且返回一个status错误码,其值为1。

练习 1.7

函数调用io.Copy(dst, src)会从src中读取内容,并将读到的结果写入到dst中,使用这个函数替代掉例子中的ioutil.ReadAll来拷贝响应结构体到os.Stdout,避免申请一个缓冲区(例子中的b)来存储。记得处理io.Copy返回结果中的错误。

练习 1.8

修改fetch这个范例,如果输入的url参数没有http://前缀的话,为这个url加上该前缀。你可能会用到strings.HasPrefix这个函数。

练习 1.9

修改fetch打印出HTTP协议的状态码,可以从resp.Status变量得到该状态码。
gopl_fetch_ex1.go (ex1.7~1.9)

// Fetch prints the content found at a URL.
package mainimport ("fmt""io""net/http""os""strings"
)func main() {for _, url := range os.Args[1:] {if !strings.HasPrefix(url, "http://") {url = "http://" + url}resp, err := http.Get(url)if err != nil {fmt.Fprintf(os.Stderr, "fetch: %v\n", err)os.Exit(1)}b, err := io.Copy(os.Stdout, resp.Body)resp.Body.Close()if err != nil {fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)os.Exit(1)}fmt.Printf("%d", b)fmt.Printf("%s", resp.Status)}
}

Go语言特性

  • 并发编程
    Go语言提供了基于CSP的并发特性支持。Go语言的动态栈使得轻量级线程goroutine的初始栈可以很小,因此,创建一个goroutine的代价很小,创建百万级的goroutine完全是可行的。go使用 goroutineschannels 处理并发编程。

  • 标准库(语言自带的电池)
    I/O操作、文本处理、图像、密码学、网络和分布式应用程序等,并支持许多标准化的文件格 式和编解码协议。

  • 切片
    为动态数组提供了有效的随机存取的性能

  • 其它

    1. 词法作用域
    2. 嵌套函数
    3. 自动垃圾回收
    4. 包系统
    5. 函数作为一等公民
    6. 系统调用接口
    7. 只读的UTF8字符串
    8. 多返回值
    

    没有的特性:隐式的数值转换,构造函数和析构函数,运算符重载,默认参数,继承(go使用组合简单对象来构建复杂对象。具体类型和抽象类型(接口)间的关系是隐式的),泛型,异常,宏,函数修饰,线程局部存储

顺序通信进程(communicating sequential processes,CSP):一组中间没有共享状
态的平行运行的处理过程,它们之间使用管道进行通信和控制同步。

《Go语言圣经》第一章:入门-习题解答及读书笔记精华摘要相关推荐

  1. pdf 天线理论与技术 钟顺时_天线理论与技术第二版-钟顺时-第一章部分习题解答.pdf...

    天线理论与技术第二版-钟顺时-第一章部分习题解答 第一次作业 Matlab 绘制电基本振子方向图和E 面H 面 1 1.1-1 ̅ ( ) ̅ ̅ ∇ × = ∇ × [ ] = − [( )] ̅ ...

  2. sicp第一章部分习题解答

    (begin(load "util.scm");ex 1.16 计算b的幂 (define (_expt product b n maxn)(if (= n maxn) produ ...

  3. 《战略管理》第一章什么是战略管理读书笔记

    一.什么是战略 战略:设计用来开发核心竞争力.获取竞争优势的一系列的综合的.协调的约定和行动. 战略管理过程:一家公司想要获取战略竞争力和超额利润而采用的一整套约定.决策和行动. 当选择了一种战略,公 ...

  4. 一段c语言的自加程序输出xyz,c语言程序设计基础教程_习题解答2012.doc

    c语言程序设计基础教程_习题解答2012 C语言程序设计基础教程_习题答案2012 习题答案 第1章 填空题 应用程序ONEFUNCC中只有一个函数这个函数的名称是__main 一个函数由__函数头_ ...

  5. c语言编程指法输入,C语言 课件 第一章引论.pdf

    C语言 课件 第一章引论 我很高兴为同学们上C语言课 我希望同学们有 良好的课堂纪律,给老师一个好心情: 让我先谢谢同学们的良好合作: 师生共努力,教好学好C语言; 学会编程更有利于数学的应用; 学习 ...

  6. 机器学习 周志华 第一章课后习题

    机器学习 周志华 第一章课后习题 1.1 1.2 1.3 1.4 1.5 1.1 在下面这张图片中若只包含编号为1和4的两个样例,试给出相应的版本空间. 书上实例: 1.表 1.1 对应的假设空间如下 ...

  7. 操作系统——精髓与设计原理 第一章复习题习题

    操作系统--精髓与设计原理 第一章复习题&习题 复习题 1.1 列出并简要地定义计算机的四个主要组成部分 1.2定义处理器寄存器的两种主要类别 1.3一般而言,一条机器指令能指定的四种不同的操 ...

  8. linux课后作业答案第六章,操作系统 第六章作业习题解答

    第六章作业习题解答 3.某操作系统的磁盘文件空间共有500块,若用字长为32位的位示图管理盘空间,试问: (1)位示图需多少个字? (2)第i字第j位对应的块号是多少? (3)并给出申请/归还一块的工 ...

  9. .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

    写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员的自白 这篇文章会这么火,更没想到的是张善友队长的公众号居然也转载了这篇文章,这就导致两天的时间就有两百多位读者朋友加 ...

最新文章

  1. 《面向对象程序设计》c++第五次作业___calculator plus plus
  2. linux 硬链接和软链接
  3. 2018蓝桥杯省赛java_蓝桥杯2018年A组省赛
  4. cocos2d-x初探学习笔记(7)--CCProgressTimer
  5. ASP.NET里创建Microsoft Word文档
  6. django开源电子文档管理系统_Python实操技术分享:Django文件管理系统,Apple的学习思路...
  7. Hello IPv6
  8. rtsp连接断开_live555_RTSP连接建立以及请求消息处理过程
  9. Eclipse下Pydev在线安装失败及解决办法
  10. Windows核心编程_LOG软件
  11. typescript 爬坑速记
  12. emule服务器无响应,全部服务器无响应!!!
  13. 机器人领域的SCI期刊和会议
  14. cgi加载java class_深入研究Java类加载机制
  15. 金刚经原文、注释、译文完整版
  16. Gene Pattern
  17. Collection集合家族
  18. 微信编辑器自带阅读鼓励金,让阅读更有意思!
  19. 计算机在中学物理的应用分析报告,信息技术在初中物理教学中的应用
  20. PHP菜刀在线WEB版源码

热门文章

  1. http综合实验-搭建openlab网站
  2. ftp上传显示服务器错误,FTP文件夹错误:打开FTP服务器上的文件夹时发生错误
  3. 希尔顿惠庭“旅居”品类酒店打造酒店界投资行业标杆
  4. 2010-02-28 传智播客—Android(三)数据存储之三SQLite嵌入式数据库
  5. 常用的新媒体工具有哪些?
  6. 三网融合CPE不插卡实现全网通上网
  7. NLP自然语言处理简介
  8. smobiler仿饿了么app搜索页面
  9. 秋春招总结之并发多线程
  10. STM32F1与STM32CubeIDE快速入门-ADC轮询方式实现PWM调光器