Go语言Tips
转型到Go以后,因为语言的不熟悉,以往很常见的一些操作有时候也需要去Google一下。这里将一些结果记录下来,方便日后查阅。
这篇文章没有什么讲解,都是一些小例子,有点类似于:go by example
如何获取Go routine的ID
不像其他语言,go本身不提供类似Thread.CurrentTread.ThreadId这样的函数,因此无法直接获得go routine的ID。但在调试时,我们有时候需要输出Go routine的ID,可以使用这个方法:
func GoID() int { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("无法获得: %v", err)) } return id } func runTest() { for i := 0; i < 10; i++ { go func() { fmt.Println("GoId:", GoID()) }() } }
其实在调试时,我们主要关心的是能够区分出各个Go routine,而不关心Id的具体值。此时,可以用下面的方法,自己给每个routine提供一个id,这个方法更简单,也就不需要GoID方法了。
func runTest() { for i := 0; i < 10; i++ { go func(id index) { fmt.Println("GoId:", id) }(i) } }
如何判断interface{}的类型
有时候,我们需要一个通用的方法,接收interface{}类型,然后再进行类型转换。在go中,可以通过称为type switch的语法来完成:
func typeSwitch(x interface{}) { switch a := x.(type) { case int: fmt.Printf("%v is int\n", a) case string: fmt.Printf("%v is string\n", a) default: fmt.Printf("%v is interface{}\n", a) } }
上面这段代码的神奇之处在于:你不需要再进行类型转换,变量a就已经转换为了相应的类型。即:在case int:代码段中a是int(可以调用接受int类型的函数);在 case string: 代码段中,a又变成了string。
如何解析XML?
我没有找到类似C#中的xml API可以动态地解析xml结构, 或者通过XPath来对xml结构进行搜索。只能一次性映射成一个struct,然后通过struct的属性去访问,这样每次解析都要构建一个对应的struct,稍显麻烦,可能有更好的解决方案,只是我不知道吧。
好处是,即使xml和struct并不完全对应,也可以正确解析,否则就会变得无比麻烦。
// Root 根节点 type Root struct { XMLName xml.Name `xml:"xml"` ReturnCode string `xml:"return_code"` ReturnMsg string `xml:"return_msg"` ResultCode string `xml:"result_code"` ErrCode string `xml:"err_code"` ErrCodeDes string `xml:"err_code_des"` CodeURL string `xml:"code_url"` } func testXML() { xmlStr := `<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[Native]]></trade_type> <code_url><![CDATA[weixin://wxpay/s/An4baqw]]></code_url> </xml>` xmlByte := []byte(xmlStr) var root Root xml.Unmarshal(xmlByte, &root) fmt.Println(root.ReturnCode) fmt.Println(root.CodeURL) fmt.Println("root.ErrCode", root.ErrCode) // 这个是没有的 }
如何将各种类型转换成字符串?
Go的字符串类型转换有时候真的是让萌新有点犯晕。
func convertToString() { var text string // int 转换成字符串 text = strconv.Itoa(10000) fmt.Println("text:", text) // interface{} 转换成字符串 var i interface{} i = "hello" text = i.(string) fmt.Println("text:", text) // byte[] 转换成字符串 data := []byte("world") text = string(data) fmt.Println("text:", text) }
如何生成随机数?如何用某一字符补齐特定长度字符串?
这个小小的以日期+随机数作为唯一编号的函数包含了这两个功能。
func GetDateNo() string { // 生成随机数:0~9999 src := rand.NewSource(time.Now().UnixNano()) r := rand.New(src) suffix := strconv.Itoa(r.Intn(10000)) // 最大长度为4,并且用0来补齐 if len(suffix) < 4 { suffix = fmt.Sprintf("%04s", suffix) } str := time.Now().Format("060102150405") + suffix return str }
如何对map按照key进行排序?
无法对map进行排序,如果需要按顺序处理map,可以用下面的方法间接进行。
// 对map进行排序 func sortMap(dic map[string]string) { var keys []string for k := range dic { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { // 在这里进行处理 fmt.Println(k, ":", dic[k]) } }
如何生成Md5加密字符串?
// GetMd5 获得md5字符串 func GetMd5(text string) string { data := []byte(text) cryptoData := md5.Sum(data) cryptoText := hex.EncodeToString(cryptoData[:]) return cryptoText }
如何获取当前程序的运行目录?
func main() { dir, err := filepath.Abs(filepath.Dir(os.Args[0])) if err != nil { log.Fatal(err) } fmt.Println("Path:", dir) }
如何获取当前的GOPATH路径?
func main(){ fmt.Println(build.Default.GOPATH) }
如何发起HttpGet请求,并以字符串返回结果?
// HTTPGet 发起HttpGet请求,并返回string格式的结果 func HTTPGet(url string) (string, error) { res, err := http.Get(url) if err != nil { log.Error(err.Error(), "HTTPGet") return "", err } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { log.Error(err.Error(), "HTTPGet") return "", err } return string(body), nil }
如何发起HttpPost请求,并以字符串返回结果?
// HTTPPost 发起http post请求 func HTTPPost(url string, body string) (string, error) { data := []byte(body) reader := bytes.NewReader(data) res, err := http.Post(url, "application/x-www-form-urlencoded", reader) if err != nil { log.Error(err.Error(), "HTTPPost-1") return "", err } resBody, err := ioutil.ReadAll(res.Body) if err != nil { log.Error(err.Error(), "HTTPPost-2") return "", err } return string(resBody), nil }
如何生成QR二维码
首先 go get github.com/boombuler/barcode
,然后看下面范例。
package main import ( "bytes" "fmt" "image/png" "os" "github.com/boombuler/barcode" "github.com/boombuler/barcode/qr" )
生成QR图片
func createQRImage() { qrCode, _ := qr.Encode("http://www.baidu.com", qr.M, qr.Auto) qrCode, _ = barcode.Scale(qrCode, 200, 200) file, _ := os.Create("qrcode.png") defer file.Close() png.Encode(file, qrCode) }
生成QR byte数组(应该更常用一些,可以直接http返回)
func createQRByte() []byte { qrCode, _ := qr.Encode("http://www.baidu.com", qr.M, qr.Auto) qrCode, _ = barcode.Scale(qrCode, 200, 200) buf := new(bytes.Buffer) png.Encode(buf, qrCode) bytes := buf.Bytes() return bytes }
如何正确转换日期?
因为我们的时区是UTC+8,所以关于时间,如果不小心处理就会出现相差8小时的错误。看下面的代码:
func main() { const LayOut = "2006-01-02 15:04:05" // 获取当前日期并转换为字符串打印 now := time.Now() nowStr := now.Format(LayOut) fmt.Println(nowStr) // 将字符串转换为日期,再转换回去然后打印 now2, _ := time.Parse(LayOut, nowStr) now2Str := now2.Format(LayOut) fmt.Println(now2Str) diff := now.Sub(now2) fmt.Println("total :", diff.Hours()) }
按正常理解,这样转换后的结果应该是完全一致的,结果实际上now比now2早了8小时。
2017-12-14 14:53:00 2017-12-14 14:53:00 total : -7.999736999166666
字符串的值完全相等,但是diff一下发现实际不一样。其实将上面的例子稍微修改一下,就知道差别了:
// 相同代码省略 fmt.Println(now.String()) fmt.Println(now2.String())
输出为:
2017-12-14 15:05:12.3921453 +0800 CST 2017-12-14 15:05:12 +0000 UTC total : -7.99989107075
可以看到两个时间是不一样的,所以在从字符串转换为日期的时候,需要将当前时区传进去,这里是正确版本:
Beijing, _ := time.LoadLocation("Asia/Shanghai") now2, _ := time.ParseInLocation(LayOut, nowStr, Beijing) fmt.Println(now2.String())
如何获取当前URL?
本想通过url.URL获取当前URL全路径,结果本地(localhost)测试时,scheme为空,host为空,所以通过http.Request来获得,结果scheme还是空。没有啥其他办法,暂时写死了。
func getFullURL(r *http.Request) string { return "http://" + r.Host + r.RequestURI // return r.URL.Scheme + "://" + r.Host + r.RequestURI }
感谢阅读,希望这篇文章能给你带来帮助!