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循环有多种形式:
其中的一种为:
可以变化为:whilefor initialization; condition; post { // zero or more statements }
无限循环:// a traditional "while" loop for condition { // ... }
for 循环的另一种形式, 在某种数据类型的区间( range) 上遍历,如:// a traditional infinite loop for { // ... }
此处使用了空标识符(blank identifier),即_(下划线),原因是go语言不允许使用无用的局部变量for _, arg := range os.Args[1:] { s += sep + arg sep = " " }
- 声明一个变量有好几种方式,下面这些都等价:
一种形式,是一条短变量声明,最简洁,但只能用在函数内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之间进行参数传递:
当一个goroutine尝试在一个channel上做send或者receive操作时,这个goroutine会阻塞在调用处,直到另一个goroutine往这个channel里写入、或者接收值,这样两个goroutine才会继续执行channel操作之后的逻辑,往channel里发送一个值(ch<-experession),接收值(<-ch)ch := make(chan string)
ch <- fmt.Sprintf("while reading %s: %v", url, err) .... fmt.Println(<-ch)
7.Web服务
- 例子中有:
其中 *http.Request等同于c语言的指针,文章中并未进行说明,特此记录。func handler(w http.ResponseWriter, r *http.Request) {
- 服务器每一次接收请求处理时都会另起一个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多路选择说明:
Go语言并不需要显式地在每一个case后写break,语言默认执行完case后的逻辑语句会自动退出。如果你想要相邻的case都执行同一逻辑的话,需要自己显式地写上一个fallthrough语句来覆盖这种默认行为.switch coinflip() { case "heads": heads++ case "tails": tails++ default: fmt.Println("landed on edge!") }
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/pkg 和 https://godoc.org中找到标准库和社区写的package。godoc这个工具可以让你直接在本地命令行阅读标准库的文档
- 注释: 参考10.7.4
扫一扫关注微信公众号:耿直的IT男阿斌
聊一聊IT男眼中的世界