Golang -- 10件你不知道的事情

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

本文翻譯 從 文章進行翻譯,在此表示感謝

10 things you (probably) don’t know about golang

匿名結構體 (Anonymous structs)

Template data (模板資料)

data := struct {    Title string    Users []*User //猜測 User 是一個介面,介面指標的切片} {    title,    USERS,}err := tmpl.Execute(w, data)

(Cheaper and safer than using map[string]interface{})
確實沒有太理解,是什麼意思?

嵌入式鎖 (Embedded Lock)

var hits struct{    sync.Mutex   //匿名對象的方法,(類似於一種繼承的方式)    n int}hits.Lock()  // (和C++中的繼承很類似)hits.n++hits.Unlock()

Nested structs 嵌套的結構

Decoding deeply nested JSON data

{"data" : {"children" : [ {"data" : {  "title" : "The Go homepage",  "url" : "http://golang.org/"}}  ,  ...  ]}}
type Item struct{    Titel  string    URL    string}type Response struct{  //使用 Structs 來表示 Json 資料,十分巧妙    Data struct {        Children []struct {            Data Item        }    }}記得在 golang的 json 庫中,既可以直接使用這樣的結構來進行 JSON 資料的解析和發送。

Command-line godoc 命令列 godoc

% godoc sync Mutex //這裡 godoc 是命令,sync是包名, Mutex是類型名

顯示值如下

type Mutex struct {
// contains filtered or unexported fields }
A Mutex is a mutual exclusion lock. Mutexes can be created as part of
other structures; the zero value for a Mutex is an unlocked mutex.

func (m *Mutex) Lock()
Lock locks m. If the lock is already in use, the calling goroutine
blocks until the mutex is available.

func (m *Mutex) Unlock()
Unlock unlocks m. It is a run-time error if m is not locked on entry to
Unlock.

A locked Mutex is not associated with a particular goroutine. It isallowed for one goroutine to lock a Mutex and then arrange for anothergoroutine to unlock it.

godc -src 可以直接顯示golang的原始碼

% godoc -src sync Mutex

顯示如下:

// A Mutex is a mutual exclusion lock. // Mutexes can be created as
part of other structures // the zero value for a Mutex is an unlocked
mutex. type Mutex struct {
state int32
sema uint32 }// Local per-P Pool appendix. type poolLocal struct {
Mutex // Protects shared.
// contains filtered or unexported fields }

可以看到,顯示了 unexported state! 便於我們對原始碼進行深入的探索.

Mock out the file system (模仿檔案系統)

現在有一個 package,這個包需要和 file system 進行協作,但是你不想讓你的測試使用真正的磁碟,應該怎麼辦?

var fs fileSystem = osFS{}type fileSystem interface {  //應該是標準庫中檔案系統的介面    Open(name string) (file, error)    Stat(name string) (os.fileInfo, error)}type file interface { //標準庫 中 file的介面    io.Closer    io.Reader    io.ReaderAt    io.Seeker    Stat() (os.FileInfo, error)}type osFs struct{} // osFs 類型,實現了 fileSystem 介面。func (osFs) Open(name string) (file, error)  //只要它的傳回值,實現file介面即可func (osFs) Stat(name string) (os.FileInfo, error) 

Method expression (方法運算式)

type T struct{}  //定義了一個新的類型 Tfunc (T) Foo(string) {fmt.Println(s)}  //定義了這個類型T的一個方法//fn 是一個函數類型的變數,將這個方法賦值給這個變數// 值得注意的是: fn 的類型是 func(T, string)// Foo 函數的類型是: func (T) Foo(string) 類型var fn func(T, sring) = T.Foo  

os/exec 中的一個真實的例子:

func (c *Cmd) stdin() (f *os.File, error)func (c *Cmd) stdout() (f *os.File, error)func (c *Cmd) stderr() (f *os.File, error)type F func(*cmd) (*os.File, error)for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} { //定義了一個切片    fd, err := steupFd(c)    if err != nil {        c.closeDescriptors(c.closeAfterStart)        c.closeDescriptors(c.closeAfterWait)        return err    }    c.childFiles = append(c.childFiles, fd)}

Send and receive on the same channel

package mainimport "fmt"var battle = make(chan string) //定義一個 channel 變數func warrior(name string, done chan struct{}) {    //現在問題來了:同一個select中,同一個 channel的情況應該如何應對?    select {    case oppoent := <-battle:  //battle 接受資料        fmt.Printf("%s beat %s\n", name, oppoent)    case battle <- name:  //battle 發送資料        // I lost    }    done <- struct{}{}}func main() {    done := make(chan struct{})    langs := []string{"Go", "C", "C++", "Java", "Perl", "Python"}    for _, s := range langs {        go warrior(s, done) //產生多個 Goroutine    }    for _ = range langs {        <-done  //等待 Goroutine結束, 什麼時候整個進程結束?    }}

多次運行程式,輸出並不一樣:
第一次運行:

Java beat C++
Go beat C
Perl beat Python

第二次運行:

Python beat Perl
Go beat C
C++ beat Java

現在問題是:
1. 在同一個Select中,如果同時又兩個 或者兩個 以上的 case 語句中: 同樣一個 channel 進行接收資料 會怎麼樣?
2. 同樣一個 channel 同時發送資料,會怎麼樣?
3. 同樣一個 channel (發送 和 接收 ) 資料,會怎麼樣? 會有自發自收的現象嗎?

自己的猜測:
1. 如果有兩個 channel 同時發送資料,會隨機播放一個 channel 進行發送資料
2. 如果有兩個 channel 同時接收資料,會隨機播放一個 channel 進行 接收資料
3. 同一個 channel (發送和接收) 資料,不會產生自發自收現象, 將會阻塞在這個 channel 中。
對於上述的例子, 具體Select是如何工作的,不太懂?(求高手指教)

Using close to broadcast (使用 close 進行廣播)

package mainimport (    "fmt"    "math/rand"  //這樣子寫    "time")func waiter(i int, block, done chan struct{}) {    time.Sleep(time.Duration(rand.Intn(3000)) * time.Millisecond)    fmt.Println(i, "waiting...")    <-block  //所有的 goroutine 會阻塞在 block這裡,直到 close(block)    fmt.Println(i, "done!")    done <- struct{}{}}func main() {    block, done := make(chan struct{}), make(chan struct{})    for i := 0; i < 4; i++ {        go waiter(i, block, done)    }    time.Sleep(5 * time.Second)    close(block)  //關閉的時候,所有阻塞的 block 將會停止阻塞 (相當於進行了一次廣播)    for i := 0; i < 4; i++ {        <-done    }}程式輸出如下:3 waiting...2 waiting...1 waiting...0 waiting...3 done!2 done!1 done!0 done!
  1. 首先 會讓所有的goroutine 阻塞 在 “<-block這裡”
  2. 當main 的Goroutine 進行 close(block)的時候,所有的block 就不會再次阻塞了
  3. 相當於 使用 close() 進行了一次廣播

NIl channel in select

func worker(i int, ch chan work, quit chan struct{}) {    for {         select {        case w :=<- ch:            if quit == nil {  //一個 channel == nil ?                w.Refuse();                fmt.Println("worker", i, "refused",w)                break;            }            w.Do();        case <-quit:            fmt.Println("worker", i, "quiting")            quit = nil (賦值成 nil)        }    }}func main() {    ch, quit := make(chan work), make(chan struct{})    go makeWork(ch)    for i := 0; i < 4; i++ {        go worker(i, ch, quit)    }    time.Sleep(5 * time.Second)    close(quit)    time.Sleep(2 * time.Second)}

上述代碼有些不太懂得地方。
1. 當一個 close(quit),之後,quit就從一個正常的 channel 變成了 nil 了嗎? (應該不是)
2. 如果 當沒有 quit 沒有返回的時候,工人永遠在幹活。
3. 當 quit 返回了自後,quit = nil,然後接下來如果要命令工人幹活,那麼工人就會退出不幹了。

總結

總體來說,比較難的地方,在於 channel 和 struct。
1. channel 的各種利用,來實現同步 和非同步,並發等功能。只能在代碼中進行探索了。
2. 有關 golang 的記憶體模型這些東西,不是很理解,很多地方不明不白的。只能等到以後慢慢理解了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.