《Google Go: A Primer》学习笔记

haishixuexiba · · 2303 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

#What is Go? simple,fast,safe and concurrent #Reading Go 编辑hello.go ``` package main import "fmt" func main(){ fmt.Println("Hello World!你好,世界!") } ``` > 经典的Hello World 运行hello.go: 方式1、 ``` go run hello.go ``` > 超快的编译速度,使得go可以像php一样执行 方式2、 ``` go build hello.go ./hello ``` > 编译执行,go可以像C、C++一样发布 #Variable Declarations ``` var sum int var total int=42 var a,b *int var label="name" name:="Samuel" ``` > 像Python一样方便的变量初始化 #Conditionals ``` result:=someFunc() if result>0{ fmt.Println("result>0") }else{ fmt.Println("result<=0") } fmt.Println(result) ``` ``` if result:=someFunc();result>0{ fmt.Println("result>0") }else{ fmt.Println("result<=0") } ``` ``` if someFunc()>0{ fmt.Println("result>0") }else{ fmt.Println("result<=0") } ``` ``` if a>0{ fmt.Println("positive") }else if a<0{ fmt.Println("negative") }else{ fmt.Println("zero") } ``` #Switches ``` byte:='b' var result int switch byte{ case 'a','b': result=1 default: result=0 } fmt.Println(result) ``` ``` switch result:=calculate();true{ case result<0: fmt.Println("negative") case result>0: fmt.Println("positive") default: fmt.Println("zero") } ``` ``` switch result:=calculate();{ case result<0: fmt.Println("negative") case result>0: fmt.Println("positive") default: fmt.Println("zero") } ``` ``` switch calculate();{ case result<0: fmt.Println("negative") case result>0: fmt.Println("positive") default: fmt.Println("zero") } ``` > 方便的switch #Loops ##Condition ``` a:=10 b:=0 for a>b{ fmt.Println(a,b) a-- b++ } ``` ##Initializer,Condition and Step ``` for i:=0;i<10;i++{ fmt.Println(i) } ``` ##Range ``` for i:=range "hello"{ fmt.Println(i) } ``` 输出0到4 ``` for i,ch:=range "hello"{ fmt.Printf("%d,%c\n",i,ch) } ``` ##Infinite ``` i:=0 for{ if i>=10{ break } fmt.Println(i) i++ } ``` > 所有编程语言中最简单的循环 #Funtions ``` func add(a,b int)int{ return a+b } fmt.Println(add(1,2)) ``` > 支持C风格的函数定义 ``` add:=func(a,b int)int{ return a+b } fmt.Println(add(1,2)) ``` > 支持匿名函数定义 ##Multiple Return Values ``` func divide(a,b int)(int,int){ quotient:=a/b remainder:=a%b return quotient,remainder } ``` ``` func divide(a,b int)(quotient,remainder int){ quotient=a/b remainder=a%b return quotient,remainder } fmt.Println(divide(7,2)) quotient,_:=divide(18,4) ``` > 支持返回值名称 ``` func moreMagic()(int,bool){ return 7,true } if result,ok:=moreMagic();ok{ fmt.Println(result) } ``` > go多返回值使错误处理变得简单、高效 ##Anonymous Functions ``` func makeAdder(x int)(func(int)int){ return func(y int)int{return x+y} } add5:=makeAdder(5) add36:=makeAdder(36) fmt.Println("The answer:",add5(add36(1))) ``` > 支持闭包,才是真正地支持匿名函数。 ``` package main import "fmt" func main(){ for i:=0;i<10;i++{ defer fmt.Println("Hello") fmt.Println("World") } } ``` 输出10个World、10个Hello > 函数结束执行defer ``` package main import "fmt" func main(){ for i:=0;i<10;i++{ func(){ defer fmt.Println("Hello") fmt.Println("World") }() } } ``` 输出10个World、Hello > defer和匿名函数可以完全实现RAII、完全实现try finally。读者可以举出RAII/try finally的例子,我采用defer和匿名函数实现。 #Primitive Types ##Arrays & Slices ``` a:=[...]int{1,2,3,4,5,6,7,8,9,0} fmt.Println(a) fmt.Println(len(a)) ``` ``` s:=a[3:5] fmt.Println(s) fmt.Println(len(s)) fmt.Println(cap(s)) s=a[3:] fmt.Println(s) fmt.Println(len(s)) fmt.Println(cap(s)) ``` > 类似Python的数组切片 ``` s[0]=42 fmt.Println(a[3]) ``` ``` s=s[1:] fmt.Println(s) ``` ``` s1:=[]int{1,2,3,4,5}; fmt.Println(s1) ``` ``` s2:=make([]int,10) fmt.Println(s2) ``` ##Maps > 内置字典非常重要。C++ STL中map采用库实现,比自己手工实现的红黑树速度慢;多线程并发需要互斥锁锁死,导致速度更慢。go的Maps线程安全,并有可能实现高效。 ``` m:=make(map[string]int) m["foo"]=42 m["bar"]=30 fmt.Println(m["foo"]) ``` > 写字典 ``` x,ok:=m["bar"] fmt.Println(x,ok) ``` > 读字典 ``` _,ok=m["baz"] fmt.Println(ok) ``` ``` m["foo"]=0 _,ok=m["foo"] fmt.Println(ok) ``` ``` delete(m,"bar") x,ok=m["bar"] fmt.Println(x,ok) ``` > 删除字典数据,可以看作一种读字典 #Object Orientation ##Structs ``` type Point struct{ x,y float64 } ``` ``` var p *Point=new(Point) fmt.Println(p) ``` ``` var p1 Point=Point{3,4} fmt.Println(p1) ``` ``` var p2 *Point=&Point{3,4} fmt.Println(p2) ``` ``` p3:=Point{3,4} fmt.Println(p3) ``` ``` p4:=&Point{3,4} fmt.Println(p4) ``` ``` p5:=&Point{x:3,y:4} fmt.Println(p5) ``` ##Methods ``` func (self *Point) SetX(x float64) { self.x = x } ``` > 修改对象需要引用语义。 ``` func (self Point) Length() float64 { return math.Sqrt(self.x*self.x + self.y*self.y) } ``` > 获取对象数据只需要值语义。 ``` p := &Point{3, 4} fmt.Println(p, p.Length()) p.SetX(5) fmt.Println(p, p.Length()) ``` ##Interfaces 面向接口很重要 > 依赖倒置原则: > 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。 > 抽象不应该依赖于具体实现,具体实现应该依赖于抽象。 ``` package main import ( "bufio" "fmt" "os" ) type Widget struct{} func (Widget)Frob(){ fmt.Println("Widget.Frob") } type Sprocket struct{} func (Sprocket)Frob(){ fmt.Println("Sprocket.Frob") } type Frobber interface{ Frob() } func frobtastic(f Frobber){ f.Frob() } func main(){ var f Frobber reader:=bufio.NewReader(os.Stdin) b,_,_:=reader.ReadLine() line:=string(b) if line=="Widget"{ f=&Widget{} }else if line=="Sprocket"{ f=&Sprocket{} }else{ return } frobtastic(f) } ``` It is important to note that every object implements the empty interface: interface {} > go实现了非嵌入式接口,即实现了模板编程,又统一了面向对象编程和模板编程。 ##Inheritance ``` type Base struct { i int } func (b Base) Magic() { fmt.Println("base magic", b.i) } func (self Base) MoreMagic() { self.Magic() self.Magic() } type Foo struct { Base } func (f Foo) Magic() { fmt.Println("foo magic", f.i) } ``` ``` f := &Foo{Base{1}} f.Magic() f.MoreMagic() ``` > 注意go的多态和C++、Java有所不同。 #Concurrency **Do not communicate by sharing memory; instead, share memory by communicating.** 不要通过共享内存来通信,而应该通过通信来共享内存。 ##Goroutines ``` package main import ("fmt";"time") func DoThis(){ for i:=0;i<10;i++{ fmt.Println("DoThis",i) time.Sleep(1e3) } } func main(){ go func(){ for i:=0;i<10;i++{ fmt.Println("func",i) time.Sleep(1e3) } }() go DoThis() time.Sleep(1e9) } ``` ##Channels ``` package main import ("fmt";"runtime") func DoThis(ch chan int){ result:=0 for i:=0;i<1000000;i++{ result+=i } ch<-result } func main(){ runtime.GOMAXPROCS(runtime.NumCPU()) ch:=make(chan int,5) go func(){ result:=0 for i:=0;i<1000000;i++{ result+=i } ch<-result }() go DoThis(ch) fmt.Println(<-ch) val,ok:=<-ch fmt.Println(val,ok) } ``` > chan是生产者消费者的一个实现。 > runtime.GOMAXPROCS支持动态设置,go多核并行。 ``` ch:=make(chan int) timeout:=make(chan bool) go func(){ time.Sleep(1e9) timeout<-true }() select{ case <-ch: fmt.Println("ch") case t:=<-timeout: fmt.Println("timeout",t) } ``` > chan可以实现超时 单向channel: ``` ch4:=make(chan int) ch5:=<-chan int(ch4) //单向读取 ch6:=chan<- int(ch4) //单向写入 ``` > C/C++中const实现语法级确定数据流向是个坑,单向channel很好地解决了这个问题。 关闭channel: ``` close(ch) ``` ``` func fibonacci(n int, c chan int) { x, y := 1, 1 for i := 0; i < n; i++ { c <- x x, y = y, x+y } close(c) } ``` ``` c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } ``` > 面向数据流编程比面向对象编程可以更清晰地解决后台问题。 让出时间片: ``` func say(s string) { for i := 0; i < 5; i++ { runtime.Gosched() fmt.Println(s) } } ``` ``` runtime.GOMAXPROCS(1) go say("World") say("Hello") ``` 同步锁:sync.Mutex、sync.RWMutex 全局唯一性操作: ``` var once sync.Once //全局 once.Do(setup) ``` > C、C++、Java、C#、go等语言都提供了单例模式的实现。 #Packages ``` src main hello.go Point Point.go ``` ``` export GOPATH=src父目录的全路径 ``` 编辑Point.go ``` Package Point import "math" type Point struct{ x,y float64 } func NewPoint(x,y float64)*Point{ return &Point{x,y} } func (self Point)Length()float64{ return math.Sqrt(self.x*self.y+self.y*self.y) } func (self *Point)Scale(factor float64){ self.setX(self.x*factor) self.setY(self.y*factor) } func (self *Point)setX(x float64){ self.x=x } func (self *Point)setY(y float64){ self.y=y } ``` 编辑hello.go ``` package main import ("fmt";"Point") func main(){ p:=Point.NewPoint(3,4) fmt.Println(p.Length()) p.Scale(10.0) fmt.Println(p.Length()) } ``` 运行: 方式一、 ``` go run hello.go ``` 方式二、 ``` go build hello.go ./hello ``` #What's Missing #总结 * go支持过程化编程、面向对象编程、函数式编程 * go支持面向接口编程、模板编程、面向数据流编程 * go语法比C更明确,比Python更简单 * go内存自动回收、defer资源回收、支持RAII、支持try finally * go简化了错误处理 * go内置了数组、数组切片、字典 * go提供了协程、生产者消费者、互斥锁、读写锁、高效多核并行 * go内置了工程管理工具 Less is more的思想正如《道德经》: ``` 大音希声,大象无形。 ```

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2303 次点击  
加入收藏 微博
6 回复  |  直到 2015-10-19 05:14:02
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传