#What is Go? simple,fast,safe and concurrent #Reading Go 編輯hello.gophp
package main import "fmt" func main(){ fmt.Println("Hello World!你好,世界!") }
經典的Hello World
運行hello.go: 方式一、編程
go run hello.go
超快的編譯速度,使得go能夠像php同樣執行
方式二、數組
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) }
##Rangeide
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",i) 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",i) 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沒有虛函數。
#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) go func() { time.Sleep(time.Second * 5) ch <- 0 }() select { case <-time.After(time.Second * 2): fmt.Println("timeout") case i := <-ch: fmt.Println(i) }
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()) }
運行: 方式1、
go run hello.go
方式2、
go build hello.go ./hello
#What's Missing #總結
大音希聲,大象無形。