golang錯題集

來源:互聯網
上載者:User

本文即Go語言的那些坑三。

不要對Go並發函數的執行時機做任何假設

請看下列的列子:

1import(2"fmt"3"runtime"4"time"5)6func main(){7names := []string{"lily","yoyo","cersei","rose","annei"}8for_, name := range names{9go func(){10fmt.Println(name)11}()12}13runtime.GOMAXPROCS(1)14runtime.Gosched()15}

請問輸出什嗎?

答案:

1annei2annei3annei4annei5annei

為什麼呢?是不是有點詫異?

輸出的都是“annei”,而“annei”又是“names”的最後一個元素,那麼也就是說程式列印出了最後一個元素的值,而name對於匿名函數來講又是一個外部的值。因此,我們可以做一個推斷:雖然每次迴圈都啟用了一個協程,但是這些協程都是引用了外部的變數,當協程建立完畢,再執行列印動作的時候,name的值已經不知道變為啥了,因為主函數協程也在跑,大家並行,但是在此由於names數組長度太小,當協程建立完畢後,主函數迴圈早已結束,所以,列印出來的都是遍曆的names最後的那一個元素“annei”。

如何證實以上的推斷呢?

其實很簡單,每次迴圈結束後,停頓一段時間,等待協程列印當前的name便可。

1import(2"fmt"3"runtime"4"time"5)6func main(){7names := []string{"lily","yoyo","cersei","rose","annei"}8for_, name := range names{9go func(){10fmt.Println(name)11}()12time.Sleep(time.Second)13}14runtime.GOMAXPROCS(1)15runtime.Gosched()16}

列印結果:

1lily2yoyo3cersei4rose5annei

以上我們得出一個結論,不要對“go函數”的執行時機做任何的假設,除非你確實能做出讓這種假設成為絕對事實的保證。

假設T類型的方法上接收器既有T類型的,又有T指標類型的,那麼就不可以在不能定址的T值上調用T接收器的方法

請看代碼,試問能正常編譯通過嗎?

1import(2"fmt"3)4type Lili struct{5Name string6}7func (Lili *Lili) fmtPointer(){8fmt.Println("poniter")9}10func (Lili Lili) fmtReference(){11fmt.Println("reference")12}13func main(){14li := Lili{}15li.fmtPointer()16}

答案:

1能正常編譯通過,並輸出"poniter"

感覺有點詫異,請接著看以下的代碼,試問能編譯通過?

1import(2"fmt"3)4type Lili struct{5Name string6}7func (Lili *Lili) fmtPointer(){8fmt.Println("poniter")9}10func (Lili Lili) fmtReference(){11fmt.Println("reference")12}13func main(){14Lili{}.fmtPointer()15}

答案:

1不能編譯通過。2“cannot call pointer method on Lili literal”3“cannot take the addressofLili literal”

是不是有點奇怪?這是為什麼呢?其實在第一個程式碼範例中,main主函數中的“li”是一個變數,li的雖然是類型Lili,但是li是可以定址的,&li的類型是Lili,因此可以調用Lili的方法。

一個包含nil指標的介面不是nil介面

請看下列代碼,試問返回什麼

1import(2"bytes"3"fmt"4"io"5)6constdebug =true7func main(){8varbuf *bytes.Buffer9ifdebug{10buf =new(bytes.Buffer)11}12f(buf)13}14func f(out io.Writer){15ifout != nil{16fmt.Println("surprise!")17}18}

答案是輸出:surprise。

ok,讓我們吧debug開關關掉,及debug的值變為false。那麼輸出什麼呢?是不是什麼都不輸出?

1import(2"bytes"3"fmt"4"io"5)6constdebug =false7func main(){8varbuf *bytes.Buffer9ifdebug{10buf =new(bytes.Buffer)11}12f(buf)13}14func f(out io.Writer){15ifout != nil{16fmt.Println("surprise!")17}18}

答案是:依然輸出surprise。

這是為什麼呢?

這就牽扯到一個概念了,是關於介面值的。概念上講一個介面的值分為兩部分:一部分是類型,一部分是類型對應的值,他們分別叫:動態類型和動態值。類型系統是針對編譯型語言的,類型是編譯期的概念,因此類型不是一個值。

在上述代碼中,給f函數的out參數賦了一個*bytes.Buffer的null 指標,所以out的動態值是nil。然而它的動態類型是bytes.Buffer,意思是:“A non-nil interface containing a nil pointer”,所以“out!=nil”的結果依然是true。

但是,對於直接的bytes.Buffer類型的判空不會出現此問題。

1import(2"bytes"3"fmt"4)5func main(){6varbuf *bytes.Buffer7ifbuf == nil{8fmt.Println("right")9}10}

還是輸出: right

只有 介面指標 傳入函數的介面參數時,才會出現以上的坑。

修改起來也很方便,把*bytes.Buffer改為io.Writer就好了。

1import(2"bytes"3"fmt"4"io"5)6constdebug =false7func main(){8varbuf  io.Writer//原來是var buf *bytes.Buffer9ifdebug{10buf =new(bytes.Buffer)11}12f(buf)13}14func f(out io.Writer){15ifout != nil{16fmt.Println("surprise!")17}18}

將map轉化為json字串的時候,json字串中的順序和map賦值順序無關

請看下列代碼,請問輸出什嗎?若為json字串,則json字串中key的順序是什嗎?

1func main() {2params := make(map[string]string)3params["id"] ="1"4params["id1"] ="3"5params["controller"] ="sections"6data, _ := json.Marshal(params)7fmt.Println(string(data))8}

答案:輸出{"controller":"sections","id":"1","id1":"3"}

利用Golang內建的json轉換包轉換,會將map中key的順序改為字母順序,而不是map的賦值順序。map這個結構哪怕利用for range遍曆的時候,其中的key也是無序的,可以理解為map就是個無序的結構,和php中的array要區分開來

Json還原序列化數字到interface{}類型的值中,預設解析為float64類型

請看以下程式,程式想要輸出json資料中整型id加上3的值,請問程式會報錯嗎?

1func main(){2jsonStr :=`{"id":1058,"name":"RyuGou"}`3varjsonData map[string]interface{}4json.Unmarshal([]byte(jsonStr), &jsonData)5sum :=  jsonData["id"].(int) +36fmt.Println(sum)7}

答案是會報錯,輸出結果為:

panic:interfaceconversion:interface{}isfloat64, notint

1使用 Golang 解析 JSON 格式資料時,若以 interface{} 接收資料,則會按照下列規則進行解析:

bool,forJSON booleansfloat64,forJSON numbersstring,forJSON strings[]interface{},forJSON arraysmap[string]interface{},forJSON objectsnilforJSONnull

1應該改為:

2go

3func main(){

4 jsonStr := {"id":1058,"name":"RyuGou"}

5 var jsonData map[string]interface{}

6 json.Unmarshal([]byte(jsonStr), &jsonData)

7 sum := int(jsonData["id"].(float64)) + 3

8 fmt.Println(sum)

9}

>>>>閱讀全文

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.