Go 语法速览与实践清单(下-V0.5)

Go 语法速览与实践清单(下-V0.5)_第1张图片

接 Go 语法速览与实践清单(上-V0.5)

Embedding

Go 语言中并没有子类继承这样的概念,而是通过嵌入(Embedding)的方式来实现类或者接口的组合。

// ReadWriter 的实现需要同时满足 Reader 与 Writer
type ReadWriter interface {
   
Reader
   
Writer
}

// Server 暴露了所有 Logger 结构体的方法

type Server struct {
   
Host string
   
Port int
   
*log.Logger

}

// 初始化方式并未受影响

server := &Server{"localhost", 80, log.New(...)}

// 却可以直接调用内嵌结构体的方法,等价于 server.Logger.Log(...)

server.Log(...)

/

/ 内嵌结构体的名词即是类型名

var logger *log.Logger = server.Logger

并发编程

Goroutines

Goroutines 是轻量级的线程,可以参考并发编程导论一文中的进程、线程与协程的讨论;Go 为我们提供了非常便捷的 Goroutines 语法:

// 普通函数

func doStuff(s string) {

}


func main() {

   // 使用命名函数创建 Goroutine

   go doStuff("foobar")

  

 // 使用匿名内部函数创建 Goroutine

   go func (x int) {

       // function body goes here

   }(42)

}

Channels

信道(Channel)是带有类型的管道,可以用于在不同的 Goroutine 之间传递消息,其基础操作如下:

// 创建类型为 int 的信道


ch := make(chan int)


// 向信道中发送值

ch <- 42


// 从信道中获取值

v := <-ch



// 读取,并且判断其是否关闭

v, ok := <-ch



// 读取信道,直至其关闭

for i := range ch {

   fmt.Println(i)

}

譬如我们可以在主线程中等待来自 Goroutine 的消息,并且输出:

// 创建信道

messages := make(chan string)



// 执行 Goroutine

go func() { messages <- "ping" }()



// 阻塞,并且等待消息

msg := <-messages



// 使用信道进行并发地计算,并且阻塞等待结果

c := make(chan int)

go sum(s[:len(s)/2], c)

go sum(s[len(s)/2:], c)

x, y := <-c, <-c // 从 c 中接收

如上创建的是无缓冲型信道(Non-buffered Channels),其是阻塞型信道;当没有值时读取方会持续阻塞,而写入方则是在无读取时阻塞。我们可以创建缓冲型信道(Buffered Channel),其读取方在信道被写满前都不会被阻塞:

ch := make(chan int, 100)

// 发送方也可以主动关闭信道
close(ch)

Channel 同样可以作为函数参数,并且我们可以显式声明其是用于发送信息还是接收信息,从而增加程序的类型安全度:

// ping 函数用于发送信息
func ping(pings chan<- string, msg string) {
   pings <- msg
}

// pong 函数用于从某个信道中接收信息,然后发送到另一个信道中
func pong(pings <-chan string, pongs chan<- string) {
   msg := <-pings
   pongs <- msg
}

func main() {
   pings := make(chan string, 1)
   pongs := make(chan string, 1)
   ping(pings, "passed message")
   pong(pings, pongs)
   fmt.Println(<-pongs)
}

同步

同步,是并发编程中的常见需求,这里我们可以使用 Channel 的阻塞特性来实现 Goroutine 之间的同步:

func worker(done chan bool) {

   time.Sleep(time.Second)

   done <- true

}



func main() {

   done := make(chan bool, 1) 

  go worker(done)



   // 阻塞直到接收到消息

   <-done

}

Go 还为我们提供了 select 关键字,用于等待多个信道的执行结果:

// 创建两个信道

c1 := make(chan string)

c2 := make(chan string)



// 每个信道会以不同时延输出不同值

go func() {

   time.Sleep(1 * time.Second)

   c1 <- "one"

}()

go func() {

   time.Sleep(2 * time.Second)

   c2 <- "two"

}()



// 使用 select 来同时等待两个信道的执行结果

for i := 0; i < 2; i++ {

   select {

   case msg1 := <-c1:

       fmt.Println("received", msg1)

   case msg2 := <-c2: 

      fmt.Println("received", msg2)

   }

}

Web 编程

HTTP Server

package main



import (

   "fmt"

   "net/http"

)



// define a type for the response

type Hello struct{}



// let that type implement the ServeHTTP method (defined in interface http.Handler)

func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {

   fmt.Fprint(w, "Hello!")

}



func main() {

   var h Hello

   http.ListenAndServe("localhost:4000", h)

}



// Here's the method signature of http.ServeHTTP:

// type Handler interface {

//     ServeHTTP(w http.ResponseWriter, r *http.Request)

// }

Beego

利用 Beego 官方推荐的 bee 命令行工具,我们可以快速创建 Beego 项目,其目录组织方式如下:

quickstart

├── conf

│   └── app.conf

├── controllers

│   └── default.go

├── main.go

├── models

├── routers

│   └── router.go

├── static│

   ├── css│

   ├── img│

   └── js

├── tests│

   └── default_test.go

└── views

   └── index.tpl

在 main.go 文件中,我们可以启动 Beego 实例,并且调用路由的初始化配置文件:

package main



import (

       _ "quickstart/routers"

       "github.com/astaxie/beego"

)



func main() {

       beego.Run()

}

而在路由的初始化函数中,我们会声明各个路由与控制器之间的映射关系:

package routers



import (

       "quickstart/controllers"

       "github.com/astaxie/beego"

)



func init() {

       beego.Router("/", &controllers.MainController{})

}

也可以手动指定 Beego 项目中的静态资源映射:

beego.SetStaticPath("/down1", "download1")

beego.SetStaticPath("/down2", "download2")

在具体的控制器中,可以设置返回数据,或者关联的模板名:

package controllers



import (

       "github.com/astaxie/beego"

)



type MainController struct {

       beego.Controller

}



func (this *MainController) Get() {

       this.Data["Website"] = "beego.me"

       this.Data["Email"] = "[email protected]"

       this.TplNames = "index.tpl" // version 1.6 use this.TplName = "index.tpl"

}

DevPractics: 开发实践

文件读写

import (

   "io/ioutil"

)

...

datFile1, errFile1 := ioutil.ReadFile("file1")

if errFile1 != nil {

   panic(errFile1)

}

...

测试

VSCode 可以为函数自动生成基础测试用例,并且提供了方便的用例执行与调试的功能。

/** 交换函数 */

func swap(x *int, y *int) {

   x, y = y, x

}



/** 自动生成的测试函数 */

func Test_swap(t *testing.T) {

   type args struct {

       x *int

       y *int

   }

   tests := []struct {

       name string

       args args

   }{

       // TODO: Add test cases.

   }

   for _, tt := range tests {

       t.Run(tt.name, func(t *testing.T) {

           swap(tt.args.x, tt.args.y)

       })

   }

}

转载|Segmentfault
感谢作者:王下邀月熊_Chevalier
原文链接:http://t.cn/Rnm6kkn

公告通知

Golang 班、架构师班、自动化运维班、区块链 正在招生中
各位小伙伴们,欢迎试听和咨询:


Go 语法速览与实践清单(下-V0.5)_第2张图片
扫码添加小助手微信,备注"公开课,来源",进入分享群

你可能感兴趣的:(Go 语法速览与实践清单(下-V0.5))