Go 語法速覽與實踐清單(下-V0.5)

上篇3D 視角看 Go 併發編程
視頻連接+PPT資料以下
連接:https://pan.baidu.com/s/1yaZp7ITQq_o01OBuGGlzwQ 密碼:f3cmcss

Embedding

Go 語言中並無子類繼承這樣的概念,而是經過嵌入(Embedding)的方式來實現類或者接口的組合。git

// 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 語法:github

// 普通函數
func doStuff(s string) {
}

func main() {
    // 使用命名函數建立 Goroutine
    go doStuff("foobar")

    // 使用匿名內部函數建立 Goroutine
    go func (x int) {
        // function body goes here
    }(42)
}

Channels

信道(Channel)是帶有類型的管道,能夠用於在不一樣的 Goroutine 之間傳遞消息,其基礎操做以下:golang

// 建立類型爲 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),其讀取方在信道被寫滿前都不會被阻塞:segmentfault

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 關鍵字,用於等待多個信道的執行結果:app

// 建立兩個信道
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 項目,其目錄組織方式以下:ide

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"] = "astaxie@gmail.com"
        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
查看原文

相關文章
相關標籤/搜索