<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 使用指針作為方法的 receiver 只要值是可尋址的,就可以在值上直接調用指針方法。即是對一個方法,它的 receiver 是指針就足矣。 但不是所有值都是可尋址的,比如 map 類型的元素、通過 interface 引用的變量: ~~~ type data struct { name string } type printer interface { print() } func (p *data) print() { fmt.Println("name: ", p.name) } func main() { d1 := data{"one"} d1.print() // d1 變量可尋址,可直接調用指針 receiver 的方法 var in printer = data{"two"} in.print() // 類型不匹配 m := map[string]data{ "x": data{"three"}, } m["x"].print() // m["x"] 是不可尋址的 // 變動頻繁 } ~~~ > cannot use data literal (type data) as type printer in assignment: > > data does not implement printer (print method has pointer receiver) > > cannot call pointer method on m\["x"\] > cannot take the address of m\["x"\] # 更新 map 字段的值 如果 map 一個字段的值是 struct 類型,則無法直接更新該 struct 的單個字段: ~~~ // 無法直接更新 struct 的字段值 type data struct { name string } func main() { m := map[string]data{ "x": {"Tom"}, } m["x"].name = "Jerry" } ~~~ > cannot assign to struct field m\["x"\].name in map 因為 map 中的元素是不可尋址的。需區分開的是,slice 的元素可尋址: ~~~ type data struct { name string } func main() { s := []data{{"Tom"}} s[0].name = "Jerry" fmt.Println(s) // [{Jerry}] } ~~~ 注意:不久前 gccgo 編譯器可更新 map struct 元素的字段值,不過很快便修復了,官方認為是 Go1.3 的潛在特性,無需及時實現,依舊在 todo list 中。 更新 map 中 struct 元素的字段值,有 2 個方法: * 使用局部變量 ~~~ // 提取整個 struct 到局部變量中,修改字段值后再整個賦值 type data struct { name string } func main() { m := map[string]data{ "x": {"Tom"}, } r := m["x"] r.name = "Jerry" m["x"] = r fmt.Println(m) // map[x:{Jerry}] } ~~~ * 使用指向元素的 map 指針 ~~~ func main() { m := map[string]*data{ "x": {"Tom"}, } m["x"].name = "Jerry" // 直接修改 m["x"] 中的字段 fmt.Println(m["x"]) // &{Jerry} } ~~~ 但是要注意下邊這種誤用: ~~~ func main() { m := map[string]*data{ "x": {"Tom"}, } m["z"].name = "what???" fmt.Println(m["x"]) } ~~~ > panic: runtime error: invalid memory address or nil pointer dereference # nil interface 和 nil interface 值 雖然 interface 看起來像指針類型,但它不是。interface 類型的變量只有在類型和值均為 nil 時才為 nil 如果你的 interface 變量的值是跟隨其他變量變化的(霧),與 nil 比較相等時小心: ~~~ func main() { var data *byte var in interface{} fmt.Println(data, data == nil) // <nil> true fmt.Println(in, in == nil) // <nil> true in = data fmt.Println(in, in == nil) // <nil> false // data 值為 nil,但 in 值不為 nil } ~~~ 如果你的函數返回值類型是 interface,更要小心這個坑: ~~~ // 錯誤示例 func main() { doIt := func(arg int) interface{} { var result *struct{} = nil if arg > 0 { result = &struct{}{} } return result } if res := doIt(-1); res != nil { fmt.Println("Good result: ", res) // Good result: <nil> fmt.Printf("%T\n", res) // *struct {} // res 不是 nil,它的值為 nil fmt.Printf("%v\n", res) // <nil> } } // 正確示例 func main() { doIt := func(arg int) interface{} { var result *struct{} = nil if arg > 0 { result = &struct{}{} } else { return nil // 明確指明返回 nil } return result } if res := doIt(-1); res != nil { fmt.Println("Good result: ", res) } else { fmt.Println("Bad result: ", res) // Bad result: <nil> } } ~~~ # 堆棧變量 你并不總是清楚你的變量是分配到了堆還是棧。 在 C++ 中使用`new`創建的變量總是分配到堆內存上的,但在 Go 中即使使用`new()`、`make()`來創建變量,變量為內存分配位置依舊歸 Go 編譯器管。 Go 編譯器會根據變量的大小及其 "escape analysis" 的結果來決定變量的存儲位置,故能準確返回本地變量的地址,這在 C/C++ 中是不行的。 在 go build 或 go run 時,加入 -m 參數,能準確分析程序的變量分配位置: ![](https://img.kancloud.cn/97/28/9728ff41e02986385352ad03bebdd2d7_411x185.png) # GOMAXPROCS、Concurrency(并發)and Parallelism(并行) Go 1.4 及以下版本,程序只會使用 1 個執行上下文 / OS 線程,即任何時間都最多只有 1 個 goroutine 在執行。 Go 1.5 版本將可執行上下文的數量設置為`runtime.NumCPU()`返回的邏輯 CPU 核心數,這個數與系統實際總的 CPU 邏輯核心數是否一致,取決于你的 CPU 分配給程序的核心數,可以使用`GOMAXPROCS`環境變量或者動態的使用`runtime.GOMAXPROCS()`來調整。 誤區:`GOMAXPROCS`表示執行 goroutine 的 CPU 核心數,參考[文檔](https://golang.org/pkg/runtime/) `GOMAXPROCS`的值是可以超過 CPU 的實際數量的,在 1.5 中最大為 256 ~~~ func main() { fmt.Println(runtime.GOMAXPROCS(-1)) // 4 fmt.Println(runtime.NumCPU()) // 4 runtime.GOMAXPROCS(20) fmt.Println(runtime.GOMAXPROCS(-1)) // 20 runtime.GOMAXPROCS(300) fmt.Println(runtime.GOMAXPROCS(-1)) // Go 1.9.2 // 300 } ~~~ # 讀寫操作的重新排序 Go 可能會重排一些操作的執行順序,可以保證在一個 goroutine 中操作是順序執行的,但不保證多 goroutine 的執行順序 ~~~ var _ = runtime.GOMAXPROCS(3) var a, b int func u1() { a = 1 b = 2 } func u2() { a = 3 b = 4 } func p() { println(a) println(b) } func main() { go u1() // 多個 goroutine 的執行順序不定 go u2() go p() time.Sleep(1 * time.Second) } ~~~ ![](https://img.kancloud.cn/9b/41/9b4150eacc3c04771d44fe7358411cec_193x210.png) 如果你想保持多 goroutine 像代碼中的那樣順序執行,可以使用 channel 或 sync 包中的鎖機制等。 # 優先調度 你的程序可能出現一個 goroutine 在運行時阻止了其他 goroutine 的運行,比如程序中有一個不讓調度器運行的`for`循環: ~~~ func main() { done := false go func() { done = true }() for !done { } println("done !") } ~~~ `for`的循環體不必為空,但如果代碼不會觸發調度器執行,將出現問題。 調度器會在 GC、Go 聲明、阻塞 channel、阻塞系統調用和鎖操作后再執行,也會在非內聯函數調用時執行: ~~~ func main() { done := false go func() { done = true }() for !done { println("not done !") // 并不內聯執行 } println("done !") } ~~~ 可以添加`-m`參數來分析`for`代碼塊中調用的內聯函數: ![](https://img.kancloud.cn/34/de/34de87a87fd5a2e9c0ff41414f137181_358x278.png) 你也可以使用 runtime 包中的`Gosched()`來 手動啟動調度器: ~~~ func main() { done := false go func() { done = true }() for !done { runtime.Gosched() } println("done !") } ~~~ 運行效果: ![](https://img.kancloud.cn/a9/23/a92333acabc7a225d4762caa0188f78d_358x179.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看