Go 回答彙總三

第三篇 Go 問答總結,2019 年 8 月份總結,大約有 12 篇問答。前兩遍地址如下:

Go 問答彙總一
Go 問答彙總二

問題大部分是來自於知乎和 segmentfault。本月有一個問題來自 stackoverflow,我的英文水平一般,讀與翻譯還行,但寫起來還需要鍛鍊。雖然這一個回答沒得到一個贊同,但能被題主採納,我還是很榮幸的。

最近發現,我的回答經常會被 Go 語言中文網的週刊收錄。對 Go 感興趣的朋友可以關注下 Go 語言中文網的公衆號,內容還是非常豐富的,每天都會推送關於 Go 的優秀文章。

clipboard.png

開始正文!

dynamodbattribute.UnmarshalMap canges the type of my variable to map[string]interface{}

將 stackoverflow 的這篇回答放在首位吧,問題不是很難,重在第一次嘗試,stackoverflow 上面有價值的問題還是很多的。

題主的目標是希望 map 類型轉化成 struct 類型。將問題稍微簡化下,題主希望通過類似如下這種寫法將 map[string]interface{} 轉化爲 user 類型。

package main

import "fmt"

type User struct {
    Name string
}

func Item() interface{} {
    return User{}
}

func ItemMap(s map[string]interface{}, item *interface{}) {
    *item = s
}

func main() {
    m := Item()
    fmt.Printf("%T\n", m)
    fmt.Printf("%v\n", m)

    s := map[string]interface{}{
        "Name": "poloxue",
    }
    ItemMap(s, &m)

    fmt.Printf("%T\n", m)
    fmt.Printf("%v\n", m)
}

首先,通過 Item() 方法創建一個 User 類型變量,但返回的類型是 interface{},因而 main 主函數中的 m 通過類型推導,也就是 interface{} 類型,在 ItemMap 函數中將 map[string]interface{} 變量賦值給 m 的地址並不會有任何問題,因爲雖然此時 m 類型的底層類型是 User,但賦值時並不會驗查到這一層,經過一部分之後,m 的底層類型就由 User 轉化成了 map[string]interface,並非完成了 map[string]interface{} 到 struct 的轉化。

看樣子,map 和 struct 的轉化還是很常見的需求啊,上月的問答總結就有類似的問題。再次推薦 mapstructure 包。

go源碼的raceenable是做什麼的,可否解答一二!

Go 是內置併發支持的語言,併發的常見問題就是出現競態條件,Go 專門提供了一個工具用於檢測這個問題,使用非常方便,只需要在執行程序時加上 -race 選項,Go 源碼中的這個 raceenable 表示的意思即使是否啓用了 raceenable。

前段時間翻譯了一篇關於 go race 的文章,訪問 Go 譯文之競態檢測器 race

Golang中,runtime.Caller(skip),爲什麼會保留編譯器變量?

題主的目標是獲取 Go 可執行文件的當前路徑,但對於很多習慣了使用解釋型語言的朋友,養成了源碼文件路徑即可執行文件路徑的思維,而 runtine.Caller 可用於查看調用棧信息,正好可以保留編譯時的源碼文件信息。

但真實的項目部署的肯定是可執行文件,而非源碼文件,而路徑也是針對可執行文件的路徑。如何獲取到呢?請看回答吧!

再提醒一點,正因爲很多朋友養成了解釋型語言的思維,常會通過 go run 執行源碼,然後獲取可執行文件路徑,但最終得到的確實一個看不懂的路徑。這個問題在回答也有介紹。

golang如何複用mysql連接?

golang 中的標準庫 database/sql 已經提供了一份數據庫管理的公共實現,同樣涉及 mysql 連接複用的功能。

題主的問題是爲什麼沒有達到複用的效果。

連接複用有一個重要前提就是資源使用結束後要記得釋放,否則將會一直處於佔用狀態,至於有哪些情況會導致連接一直複用,查看回答!

回答中提到了一篇非常系統介紹 Go 中 database/sql 使用的教程,有興趣可以仔細讀讀。

goroutine 出現異常

這個問題稍微有點複雜。異常的原因,簡單說來是 channel 發送者發送等待時間太長,導致異常出現。解析問題的核心思路在於,在發送者和接收之間增加一個 buffer,無論發送者發送了什麼內容,先將消息接收到 buffer 中,待有空閒的接收者時將消息從 buffer 中發送出去。

題主是通過 chan 自帶的 buffer 實現,創建了緩衝大小 50 的 chan。當然,更靈活的方式,還是自己實現 buffer 比較好。而且題主的場景是爬蟲,可能對 buffer 的大小要求會比較高,可能適當考慮接入外部服務。

go的reflect是否可以獲取到同一個package中,其他文件定義的類型的私有方法的名稱?

首先,要明確的是,Go 中的反射是無法看到類型的私有方法的。如果想達到這個目標,只能將方法定義爲可導出方法。但私有方法也有它的好處,那就是外界無法使用這個方法。那將方法定義爲公開可導出是否也可以做到讓外界無法使用?

查看我的回答吧!

beego 的緩存如何轉結構體呢?

beego 中緩存的存儲與獲取的問題,很簡單,沒什麼好說的!

go語言裏的select監聽到底是怎麼工作的?

問題的核心不在於 select 的工作機制,而是關於 Go 中 timer 定時器的使用問題。以下是問題的核心代碼。

for {
    select {
        case num := <-ch:
            fmt.Println("get num is ", num)
        case <-time.After(2 * time.Second):
            fmt.Println("time's up!!!")
            //quit <- true
        }
    }
}()

題主的問題是爲什麼 timer 的 case 一直沒有執行。這是因爲 time.After 在每次循環都會創建的 chan,之前定時 chan 已經不再監聽了。

我開始覺得,這種方式挺適合處理任務出現 timeout 的情況,經過一位朋友提醒,這裏面存在着泄露風險。具體原因,閱讀回答瞭解吧!

在golang的設計裏,爲什麼不能用switch實現select的功能?

主要是場景決定吧,channel 監聽有點類似於異步 IO 的多路複用,select 可以說是多路複用的專用名字了,switch 是分支結構,硬要加上其他功能,也不便於理解,我的感覺是,獨立出一個新的關鍵字會更好理解。

go語言struct中有函數指數的示例講解

題主要求用從淺入深的方式介紹,Go 中 struct 含有函數成員的問題。我覺得我也寫得還不多,但是沒有得到題主的採納,只得到一個評論誇讚。

golang 編譯器分32和64版本嗎?

肯定是分的,但我們不用關心,go 命令已經封裝好了,它會依據平臺選擇不同的底層命令。

在 go 安裝目錄的 pkg 目錄下有個 tools 目錄,裏面包含了編譯鏈接時實際使用的命令,比如我的 Mac Pro,在 pkg/tool/darwin_amd64/ 下能找到 go 編譯鏈接實際調用的命令 compile 和 link。darwin_amd64 中 drawin 表示操作系統,amd64 就是系統架構。

執行 go env 會發現其中有個環境變量 GOTOOLDIR,它是那些與我們平臺相關工具的所在目錄。我的 Mac 下得到的結果是:

GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"

正則如何匹配最後一個頁碼?

題主的問題是如何進行 html 的解析。

<ul id="pages">
<li><a href="xxx1">1</a></li>
<li><a href="xxx2">2</a></li>
<li><a href="xxx3">3</a></li>
</ul>

這類問題一般是不推薦使用正則匹配,可以試試 goquery 這個庫,它的用法類似 jquery,可用於解析 html 內容,使用非常方便。當然,回答中也介紹了正則的實現,不過代碼的可讀性看起來比較差。

本月的回答總結完畢,如果大家發現有不當的內容,歡迎批評指正,非常感謝。


歡迎關注我的個人微信公衆號。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章