golang 特性簡介

sheepbao發表於2017-01-22

golang 特性簡介

by sheepbao

主要大概介紹 go 語言的歷史和特性,簡單的入門。

來歷

很久以前,有一個 IT 公司,這公司有個傳統,允許員工擁有 20% 自由時間來開發實驗性專案。在 2007 的某一天,公司的幾個大牛,正在用 c++ 開發一些比較繁瑣但是核心的工作,主要包括龐大的分散式叢集,大牛覺得很鬧心,後來 c++ 委員會來他們公司演講,說 c++ 將要新增大概 35 種新特性。這幾個大牛的其中一個人,名為:Rob Pike,聽後心中一萬個 xxx 飄過,“c++ 特性還不夠多嗎?簡化 c++ 應該更有成就感吧”。於是乎,Rob Pike 和其他幾個大牛討論了一下,怎麼解決這個問題,過了一會,Rob Pike 說要不我們自己搞個語言吧,名字叫 “go”,非常簡短,容易拼寫。其他幾位大牛就說好啊,然後他們找了塊白板,在上面寫下希望能有哪些功能(詳見文尾)。接下來的時間裡,大牛們開心的討論設計這門語言的特性,經過漫長的歲月,他們決定,以 c 語言為原型,以及借鑑其他語言的一些特性,來解放程式設計師,解放自己,然後在 2009 年,go 語言誕生。

思想

Less can be more

大道至簡,小而蘊真

讓事情變得複雜很容易,讓事情變得簡單才難

深刻的工程文化

優點

  1. 自帶 gc。
  2. 靜態編譯,編譯好後,扔伺服器直接執行。
  3. 簡單的思想,沒有繼承,多型,類等。
  4. 豐富的庫和詳細的開發文件。
  5. 語法層支援併發,和擁有同步併發的 channel 型別,使併發開發變得非常方便。
  6. 簡潔的語法,提高開發效率,同時提高程式碼的閱讀性和可維護性。
  7. 超級簡單的交叉編譯,僅需更改環境變數。(花了我兩天時間編譯一個 imagemagick 到 arm 平臺)
  8. 內含完善、全面的軟體工程工具。Go 語言自帶的命令和工具相當地強大。通過它們,我們可以很輕鬆地完成 Go 語言程式的獲取、編譯、測試、安裝、執行、執行分析等一系列工作,這幾乎涉及了開發和維護一個軟體的所有環節。

hello

package main

func main(){
    println("hello, sewise")
}

type

主要講講特有的型別,其他基本型別不做介紹

slice

切片:可以理解為動態陣列,類似 c++ 的 vector 宣告一個 slice

var slice []T

var ints []int

slice 的追加

ints=append(ints,1)
ints=append(ints,2,3,4,5)

slice 的擷取

newInts1:=ints[2:3]
newInts2:=ints[2:]
newInts3:=ints[:4]

map

字典:鍵值對

var json map[string]string

interface

介面:方法的集合,是一種合約 栗子: 宣告一個bird介面

var bird interface{
    fly()
}

宣告一個hen物件 (實現 bird 介面)

type hen struct {
    weight int
    hasFeather bool
}

func (h hen)fly(){
    fmt.Println("iI can fly")
}

type func (h hen)eat(){
    h.weight++
    fmt.Println("yes, I can eat")
}

宣告一個pig物件 (未實現 bird 介面,因為 pig 不會 fly)

type pig struct {
    age int
    weignt int
    hasFeather bool
}

func (p pig)run(){
    fmt.Println("I can run")
}

func (p pig)eat(){
    p.weight += 100
    fmt.Println("Yes, I can eat so much")
}

func (p pig)sleep(){
    fmt.Println("I slept all my life")
}

// pig can't fly

channel

通道:輕量集佇列,傳遞某種型別的值的通道

var ch chan int
ch=make(chan int,1)

往 ch 寫入一個資料

ch<-8888

從 ch 讀取資料

out:=<-ch

特性: channel 是有長度的,當 channel 的緩衝為滿時,再往裡寫入就會阻塞,當 channel 的緩衝為空時,從 channel 讀就會阻塞

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    fmt.Println("ch len:", len(ch))
    go func() {
        // 往緩衝滿的channel裡寫資料(阻塞)
        // ch <- 1
        // 從緩衝為空的channel裡讀資料(阻塞)
        <-ch
        fmt.Println("I am in minor goroutine")
    }()
    fmt.Println("I am in main goroutine")
    time.Sleep(2 * time.Second)
}

當長度為 0 是,就是不帶緩衝的 channel 長度大於 0,就是帶緩衝的 channel

併發

關鍵字:go 啟動 go 程 一個普通的函式或方法呼叫前加上關鍵字 go,即可啟動一個 goroutine

go func(){
    fmt.Println("start func")
    time.Sleep(120*time.Second)
}()

競爭條件檢測 -race race.go

package main

import (
    "fmt"
    "time"
)

func main() {
    a := 1
    go func() {
        a = 2
    }()
    a = 3
    fmt.Println("a is ", a)

    time.Sleep(2 * time.Second)
}

檢測:執行go run -race race.go

a is  3
==================
WARNING: DATA RACE
Write at 0x00c420072188 by goroutine 6:
  main.main.func1()
      /Users/bao/program/go/gowork/hello/src/research/race.go:11 +0x3b

Previous write at 0x00c420072188 by main goroutine:
  main.main()
      /Users/bao/program/go/gowork/hello/src/research/race.go:13 +0x9f

Goroutine 6 (running) created at:
  main.main()
      /Users/bao/program/go/gowork/hello/src/research/race.go:12 +0x8e
==================
Found 1 data race(s)

結果分析: goroutine6 執行到第 11 行和 main goroutine 執行到 13 行的時候觸發競爭了。而且 goroutine6 是在第 12 行的時候產生的。

package

包的管理,關鍵字importGOPATH

gopath

gopath 是一個路徑列表,存放 go 專案工程 GOPATH檔案目錄結構

├── bin  二進位制檔案目錄
├── pkg  編譯好的庫檔案目錄
└── src  原始碼目錄  

平常專案的目錄結構

├── bin  二進位制檔案目錄
├── pkg  編譯好的庫檔案目錄
└── src  原始碼目錄  
    ├── main  入口函式目錄
    └── vendor  當前專案的庫目錄
        └── sheepbao.com 
            └── glog

import

比如上面的專案,我要在main.go引入glog

package main

// 引入glog包
import "sheepbao.com/glog"

func main(){
    glog.Println("test")
}

go 的工程工具簡介

test

go 的命令工具 test,用來做測試

單元測試

go test 只測試函式名被它正確匹配的測試函式 go test -v -run="French|Canal"

栗子: add.go

package test

func addOne(i int) int {
    return i + 1
}

add_test.go

package test

import "testing"

func TestAddOne(t *testing.T) {
    result := addOne(1)
    if result != 2 {
        t.Error("1+1!=2")
    }
}
bao@baoMac test$ go test -v .
=== RUN   TestAddOne
--- PASS: TestAddOne (0.00s)
PASS
ok      _/Users/bao/program/go/gowork/hello/src/research/test   0.006s

基準測試

go test -bench=. 記憶體的分配情況 go test -bench=FuncName -benchmem 栗子: stringsCon.go

package bench

import (
    "fmt"
)

func Sprintf(s1, s2, s3 string) string {
    return fmt.Sprintf("%s%s%s", s1, s2, s3)
}

func AddString(s1, s2, s3 string) string {
    return s1 + s2 + s3
}

stringCon_test.go

package bench

import "testing"

var (
    s1 = "make it run!"
    s2 = "make it right!"
    s3 = "make it fast!"
)

func BenchmarkSprintf(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Sprintf(s1, s2, s3)
    }
}

func BenchmarkAddString(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AddString(s1, s2, s3)
    }
}

go test -bench=.

bao@baoMac bench$ go test -bench=.
testing: warning: no tests to run
BenchmarkSprintf-4       5000000               349 ns/op
BenchmarkAddString-4    20000000                61.7 ns/op
PASS
ok      _/Users/bao/program/go/gowork/hello/src/research/bench  3.414s

樣本測試

package et

import (
    "fmt"
)

func ExampleHello() {
    fmt.Println("hello, sewise")
    // Output: hello, sewise
}
bao@baoMac example$ go  test -v .
=== RUN   ExampleHello
--- PASS: ExampleHello (0.00s)
PASS
ok      _/Users/bao/program/go/gowork/hello/src/research/example        0.006s

如果把上面的// Output: hello, sewise改為// Output: hello, sewis 則樣本測試不能通過

bao@baoMac example$ go  test -v .
=== RUN   ExampleHello
--- FAIL: ExampleHello (0.00s)
got:
hello, sewise
want:
hello, sewis
FAIL
exit status 1
FAIL    _/Users/bao/program/go/gowork/hello/src/research/example        0.006s

pprof

go 的命令工具 pprof,用來效能分析(記憶體使用,洩露和 cpu 消耗) go tool pprof

  • 檢視 cpu 使用: go tool pprof http://localhost:8089/debug/pprof/profile 終端檢視: image_1b72f0lh9tir1prf1r2012codlt13.png-164.9kB

視覺化 (原是 svg 檔案,下圖為截圖):

image_1b72f233avto14d7on4h3nlm51g.png-129.8kB

  • 檢視記憶體使用 go tool pprof http://localhost:8089/debug/pprof/heap 終端檢視: image_1b72elqek180t8b315kn20hhlr9.png-177.3kB

視覺化 (原是 svg 檔案,下圖為截圖:

image_1b72euk7b1knr1d1n1ugq2pe19kim.png-176.7kB

go tool pprof --text http://localhost:6060/debug/pprof/heap

go 命令教程

資料

http://www.csdn.net/article/2012-07-04/2807113-less-is-exponentially-more

http://www.jianshu.com/p/91e40c3e3acb?hmsr=toutiao.io&amputm_medium=toutiao.io&amputm_source=toutiao.io;

http://smallsoho.com/2016/11/20/Go.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io簡明教程

大牛真身

最大牌的當屬 B 和 C 語言設計者、Unix 和 Plan 9 創始人、1983 年圖靈獎獲得者 Ken Thompson,這份名單中還包括了 Unix 核心成員 Rob Pike(go 語言之父)、java HotSpot 虛擬機器和 js v8 引擎的開發者 Robert Griesemer、Memcached 作者 Brad Fitzpatrick,等等。

功能

  • 規範的語法(不需要符號表來解析)
  • 垃圾回收(獨有)
  • 無標頭檔案
  • 明確的依賴
  • 無迴圈依賴
  • 常量只能是數字
  • int 和 int32 是兩種型別
  • 字母大小寫設定可見性(letter case sets visibility)
  • 任何型別(type)都有方法(不是型別)
  • 沒有子型別繼承(不是子類)
  • 包級別初始化以及明確的初始化順序
  • 檔案被編譯到一個包裡
  • 包 package-level globals presented in any order
  • 沒有數值型別轉換(常量起輔助作用)
  • 介面隱式實現(沒有 “implement” 宣告)
  • 嵌入(不會提升到超類)
  • 方法按照函式宣告(沒有特別的位置要求)
  • 方法即函式
  • 介面只有方法(沒有資料)
  • 方法通過名字匹配(而非型別)
  • 沒有建構函式和解構函式
  • postincrement(如 ++i)是狀態,不是表示式
  • 沒有 preincrement(i++) 和 predecrement
  • 賦值不是表示式
  • 明確賦值和函式呼叫中的計算順序(沒有 “sequence point”)
  • 沒有指標運算
  • 記憶體一直以零值初始化
  • 區域性變數取值合法
  • 方法中沒有 “this”
  • 分段的堆疊
  • 沒有靜態和其它型別的註釋
  • 沒有模板
  • 內建 string、slice 和 map
  • 陣列邊界檢查
更多原創文章乾貨分享,請關注公眾號
  • golang 特性簡介
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章