#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的思想正如《道德经》:
```
大音希声,大象无形。
```
有疑问加站长微信联系(非本文作者)