婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Go系列教程之反射的用法

Go系列教程之反射的用法

熱門標簽:高德地圖標注口訣 學海導航地圖標注 江西轉(zhuǎn)化率高的羿智云外呼系統(tǒng) 西部云谷一期地圖標注 廣州呼叫中心外呼系統(tǒng) 地圖標注的汽車標 浙江高速公路地圖標注 南通如皋申請開通400電話 中國地圖標注省會高清

反射是 Go 語言的高級主題之一。我會盡可能讓它變得簡單易懂。

本教程分為如下小節(jié)。

  • 什么是反射?
  • 為何需要檢查變量,確定變量的類型?
  • reflect 包
    • reflect.Type 和 reflect.Value
    • reflect.Kind
    • NumField() 和 Field() 方法
    • Int() 和 String() 方法
  • 完整的程序
  • 我們應(yīng)該使用反射嗎?

讓我們來逐個討論這些章節(jié)。

什么是反射?

反射就是程序能夠在運行時檢查變量和值,求出它們的類型。你可能還不太懂,這沒關(guān)系。在本教程結(jié)束后,你就會清楚地理解反射,所以跟著我們的教程學習吧。

為何需要檢查變量,確定變量的類型?

在學習反射時,所有人首先面臨的疑惑就是:如果程序中每個變量都是我們自己定義的,那么在編譯時就可以知道變量類型了,為什么我們還需要在運行時檢查變量,求出它的類型呢?沒錯,在大多數(shù)時候都是這樣,但并非總是如此。

我來解釋一下吧。下面我們編寫一個簡單的程序。

package main

import (
 "fmt"
)

func main() {
 i := 10
 fmt.Printf("%d %T", i, i)
}

在 playground 上運行

在上面的程序中,i 的類型在編譯時就知道了,然后我們在下一行打印出 i。這里沒什么特別之處。

現(xiàn)在了解一下,需要在運行時求得變量類型的情況。假如我們要編寫一個簡單的函數(shù),它接收結(jié)構(gòu)體作為參數(shù),并用它來創(chuàng)建一個 SQL 插入查詢。

考慮下面的程序:

package main

import (
 "fmt"
)

type order struct {
 ordId  int
 customerId int
}

func main() {
 o := order{
  ordId:  1234,
  customerId: 567,
 }
 fmt.Println(o)
}

在 playground 上運行

在上面的程序中,我們需要編寫一個函數(shù),接收結(jié)構(gòu)體變量 o 作為參數(shù),返回下面的 SQL 插入查詢。

insert into order values(1234, 567)

這個函數(shù)寫起來很簡單。我們現(xiàn)在編寫這個函數(shù)。

package main

import (
 "fmt"
)

type order struct {
 ordId  int
 customerId int
}

func createQuery(o order) string {
 i := fmt.Sprintf("insert into order values(%d, %d)", o.ordId, o.customerId)
 return i
}

func main() {
 o := order{
  ordId:  1234,
  customerId: 567,
 }
 fmt.Println(createQuery(o))
}

在 playground 上運行

在第 12 行,createQuery 函數(shù)用 o 的兩個字段(ordId 和 customerId),創(chuàng)建了插入查詢。該程序會輸出:

insert into order values(1234, 567)

現(xiàn)在我們來升級這個查詢生成器。如果我們想讓它變得通用,可以適用于任何結(jié)構(gòu)體類型,該怎么辦呢?我們用程序來理解一下。

package main

type order struct {
 ordId  int
 customerId int
}

type employee struct {
 name string
 id int
 address string
 salary int
 country string
}

func createQuery(q interface{}) string {
}

func main() {

}

我們的目標就是完成 createQuery 函數(shù)(上述程序中的第 16 行),它可以接收任何結(jié)構(gòu)體作為參數(shù),根據(jù)結(jié)構(gòu)體的字段創(chuàng)建插入查詢。

例如,如果我們傳入下面的結(jié)構(gòu)體:

o := order {
 ordId: 1234,
 customerId: 567
}

createQuery 函數(shù)應(yīng)該返回:

insert into order values (1234, 567)

類似地,如果我們傳入:

 e := employee {
  name: "Naveen",
  id: 565,
  address: "Science Park Road, Singapore",
  salary: 90000,
  country: "Singapore",
 }

該函數(shù)會返回:

insert into employee values("Naveen", 565, "Science Park Road, Singapore", 90000, "Singapore")

由于 createQuery 函數(shù)應(yīng)該適用于任何結(jié)構(gòu)體,因此它接收 interface{} 作為參數(shù)。為了簡單起見,我們只處理包含 string 和 int 類型字段的結(jié)構(gòu)體,但可以擴展為包含任何類型的字段。

createQuery 函數(shù)應(yīng)該適用于所有的結(jié)構(gòu)體。因此,要編寫這個函數(shù),就必須在運行時檢查傳遞過來的結(jié)構(gòu)體參數(shù)的類型,找到結(jié)構(gòu)體字段,接著創(chuàng)建查詢。這時就需要用到反射了。在本教程的下一步,我們將會學習如何使用 reflect 包來實現(xiàn)它。

reflect 包

在 Go 語言中,reflect 實現(xiàn)了運行時反射。reflect 包會幫助識別 interface{} 變量的底層具體類型和具體值。這正是我們所需要的。createQuery 函數(shù)接收 interface{} 參數(shù),根據(jù)它的具體類型和具體值,創(chuàng)建 SQL 查詢。這正是 reflect 包能夠幫助我們的地方。

在編寫我們通用的查詢生成器之前,我們首先需要了解 reflect 包中的幾種類型和方法。讓我們來逐個了解。

reflect.Type 和 reflect.Value

reflect.Type 表示 interface{} 的具體類型,而 reflect.Value 表示它的具體值。reflect.TypeOf() 和 reflect.ValueOf() 兩個函數(shù)可以分別返回 reflect.Type 和 reflect.Value。這兩種類型是我們創(chuàng)建查詢生成器的基礎(chǔ)。我們現(xiàn)在用一個簡單的例子來理解這兩種類型。

package main

import (
 "fmt"
 "reflect"
)

type order struct {
 ordId  int
 customerId int
}

func createQuery(q interface{}) {
 t := reflect.TypeOf(q)
 v := reflect.ValueOf(q)
 fmt.Println("Type ", t)
 fmt.Println("Value ", v)


}
func main() {
 o := order{
  ordId:  456,
  customerId: 56,
 }
 createQuery(o)

}

在 playground 上運行

在上面的程序中,第 13 行的 createQuery 函數(shù)接收 interface{} 作為參數(shù)。在第 14 行,reflect.TypeOf 接收了參數(shù) interface{},返回了reflect.Type,它包含了傳入的 interface{} 參數(shù)的具體類型。同樣地,在第 15 行,reflect.ValueOf 函數(shù)接收參數(shù) interface{},并返回了 reflect.Value,它包含了傳來的 interface{} 的具體值。

上述程序會打印:

Type  main.order
Value  {456 56}

從輸出我們可以看到,程序打印了接口的具體類型和具體值。

relfect.Kind

reflect 包中還有一個重要的類型:Kind。

在反射包中,Kind 和 Type 的類型可能看起來很相似,但在下面程序中,可以很清楚地看出它們的不同之處。

package main

import (
 "fmt"
 "reflect"
)

type order struct {
 ordId  int
 customerId int
}

func createQuery(q interface{}) {
 t := reflect.TypeOf(q)
 k := t.Kind()
 fmt.Println("Type ", t)
 fmt.Println("Kind ", k)


}
func main() {
 o := order{
  ordId:  456,
  customerId: 56,
 }
 createQuery(o)

}

在 playground 上運行

上述程序會輸出:

Type  main.order
Kind  struct

我想你應(yīng)該很清楚兩者的區(qū)別了。Type 表示 interface{} 的實際類型(在這里是 main.Order),而 Kind 表示該類型的特定類別(在這里是 struct)。

NumField() 和 Field() 方法

NumField() 方法返回結(jié)構(gòu)體中字段的數(shù)量,而 Field(i int) 方法返回字段 i 的 reflect.Value。

package main

import (
 "fmt"
 "reflect"
)

type order struct {
 ordId  int
 customerId int
}

func createQuery(q interface{}) {
 if reflect.ValueOf(q).Kind() == reflect.Struct {
  v := reflect.ValueOf(q)
  fmt.Println("Number of fields", v.NumField())
  for i := 0; i  v.NumField(); i++ {
   fmt.Printf("Field:%d type:%T value:%v\n", i, v.Field(i), v.Field(i))
  }
 }

}
func main() {
 o := order{
  ordId:  456,
  customerId: 56,
 }
 createQuery(o)
}

在 playground 上運行

在上面的程序中,因為 NumField 方法只能在結(jié)構(gòu)體上使用,我們在第 14 行首先檢查了 q 的類別是 struct。程序的其他代碼很容易看懂,不作解釋。該程序會輸出:

Number of fields 2
Field:0 type:reflect.Value value:456
Field:1 type:reflect.Value value:56

Int() 和 String() 方法

Int 和 String 可以幫助我們分別取出 reflect.Value 作為 int64 和 string。

package main

import (
 "fmt"
 "reflect"
)

func main() {
 a := 56
 x := reflect.ValueOf(a).Int()
 fmt.Printf("type:%T value:%v\n", x, x)
 b := "Naveen"
 y := reflect.ValueOf(b).String()
 fmt.Printf("type:%T value:%v\n", y, y)

}

在 playground 上運行

在上面程序中的第 10 行,我們?nèi)〕?reflect.Value,并轉(zhuǎn)換為 int64,而在第 13 行,我們?nèi)〕?reflect.Value 并將其轉(zhuǎn)換為 string。該程序會輸出:

type:int64 value:56
type:string value:Naveen

完整的程序

現(xiàn)在我們已經(jīng)具備足夠多的知識,來完成我們的查詢生成器了,我們來實現(xiàn)它把。

package main

import (
 "fmt"
 "reflect"
)

type order struct {
 ordId  int
 customerId int
}

type employee struct {
 name string
 id  int
 address string
 salary int
 country string
}

func createQuery(q interface{}) {
 if reflect.ValueOf(q).Kind() == reflect.Struct {
  t := reflect.TypeOf(q).Name()
  query := fmt.Sprintf("insert into %s values(", t)
  v := reflect.ValueOf(q)
  for i := 0; i  v.NumField(); i++ {
   switch v.Field(i).Kind() {
   case reflect.Int:
    if i == 0 {
     query = fmt.Sprintf("%s%d", query, v.Field(i).Int())
    } else {
     query = fmt.Sprintf("%s, %d", query, v.Field(i).Int())
    }
   case reflect.String:
    if i == 0 {
     query = fmt.Sprintf("%s\"%s\"", query, v.Field(i).String())
    } else {
     query = fmt.Sprintf("%s, \"%s\"", query, v.Field(i).String())
    }
   default:
    fmt.Println("Unsupported type")
    return
   }
  }
  query = fmt.Sprintf("%s)", query)
  fmt.Println(query)
  return

 }
 fmt.Println("unsupported type")
}

func main() {
 o := order{
  ordId:  456,
  customerId: 56,
 }
 createQuery(o)

 e := employee{
  name: "Naveen",
  id:  565,
  address: "Coimbatore",
  salary: 90000,
  country: "India",
 }
 createQuery(e)
 i := 90
 createQuery(i)

}

在 playground 上運行

在第 22 行,我們首先檢查了傳來的參數(shù)是否是一個結(jié)構(gòu)體。在第 23 行,我們使用了 Name() 方法,從該結(jié)構(gòu)體的 reflect.Type 獲取了結(jié)構(gòu)體的名字。接下來一行,我們用 t 來創(chuàng)建查詢。

在第 28 行,case 語句 檢查了當前字段是否為 reflect.Int,如果是的話,我們會取到該字段的值,并使用 Int() 方法轉(zhuǎn)換為 int64。if else 語句用于處理邊界情況。請?zhí)砑尤罩緛砝斫鉃槭裁葱枰T诘?34 行,我們用來相同的邏輯來取到 string。

我們還作了額外的檢查,以防止 createQuery 函數(shù)傳入不支持的類型時,程序發(fā)生崩潰。程序的其他代碼是自解釋性的。我建議你在合適的地方添加日志,檢查輸出,來更好地理解這個程序。

該程序會輸出:

insert into order values(456, 56)
insert into employee values("Naveen", 565, "Coimbatore", 90000, "India")
unsupported type

至于向輸出的查詢中添加字段名,我們把它留給讀者作為練習。請嘗試著修改程序,打印出以下格式的查詢。

insert into order(ordId, customerId) values(456, 56)

我們應(yīng)該使用反射嗎?

我們已經(jīng)展示了反射的實際應(yīng)用,現(xiàn)在考慮一個很現(xiàn)實的問題。我們應(yīng)該使用反射嗎?我想引用 Rob Pike 關(guān)于使用反射的格言,來回答這個問題。

清晰優(yōu)于聰明。而反射并不是一目了然的。

反射是 Go 語言中非常強大和高級的概念,我們應(yīng)該小心謹慎地使用它。使用反射編寫清晰和可維護的代碼是十分困難的。你應(yīng)該盡可能避免使用它,只在必須用到它時,才使用反射。

本教程到此結(jié)束。希望你們喜歡。祝你愉快。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • 詳解Golang編程中的常量與變量
  • Golang學習筆記(二):類型、變量、常量
  • GO語言中的常量
  • Go語言中常量定義方法實例分析
  • GOLANG使用Context實現(xiàn)傳值、超時和取消的方法
  • GOLANG使用Context管理關(guān)聯(lián)goroutine的方法
  • Go并發(fā)調(diào)用的超時處理的方法
  • Go routine調(diào)度詳解
  • 淺談GoLang幾種讀文件方式的比較
  • Golang常量iota的使用實例

標簽:吐魯番 常州 東營 德宏 許昌 貴州 曲靖 保定

巨人網(wǎng)絡(luò)通訊聲明:本文標題《Go系列教程之反射的用法》,本文關(guān)鍵詞  系列,教程,之,反射,的,用法,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Go系列教程之反射的用法》相關(guān)的同類信息!
  • 本頁收集關(guān)于Go系列教程之反射的用法的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    国产精品亲子乱子伦xxxx裸| 国产成人夜色高潮福利影视| 中文幕一区二区三区久久蜜桃| 亚洲成av人片一区二区| 国产精品护士白丝一区av| 欧美激情在线看| 日本一区二区视频在线观看| 色哟哟在线观看一区二区三区| 亚洲色图清纯唯美| 国产精品家庭影院| 亚洲欧美日韩在线| 亚洲一区二区三区视频在线| 亚洲激情自拍视频| 亚洲va国产天堂va久久en| 亚洲成av人片在www色猫咪| 轻轻草成人在线| 久久99精品国产麻豆婷婷| 国产综合久久久久久久久久久久| 国产精品久久夜| 欧美一级精品在线| 亚洲精品在线观看网站| 欧美日韩三级一区二区| 欧美高清hd18日本| 久久―日本道色综合久久| 欧美色网一区二区| 欧美大片在线观看一区二区| 国产亚洲欧美一级| 亚洲另类在线视频| 视频一区欧美精品| 国产成人h网站| 欧美色网一区二区| 国产亚洲污的网站| 亚洲成人免费视| 激情综合亚洲精品| 色综合久久66| 精品国产一区二区三区不卡| 久久蜜臀精品av| 亚洲黄色小说网站| 国产一区二区三区黄视频 | 日韩精品一区在线| 欧美色电影在线| 久久久美女毛片| 亚洲成人免费影院| 99久久国产综合精品色伊 | 蜜桃久久久久久久| 成人国产在线观看| 日韩欧美自拍偷拍| 亚洲午夜免费福利视频| 国产成人在线看| 国产69精品一区二区亚洲孕妇| 蜜臀av性久久久久蜜臀aⅴ流畅| 亚洲国产精品久久久男人的天堂| 一区二区欧美视频| 国产精品一色哟哟哟| 制服视频三区第一页精品| 欧美一级在线免费| 亚洲一区二区三区视频在线播放| 亚洲精品成a人| 成人av影院在线| 久久久久久黄色| 久久国产精品露脸对白| 欧美人狂配大交3d怪物一区| 制服丝袜av成人在线看| 欧美一区二区视频在线观看2020 | 欧美日韩在线精品一区二区三区激情 | 欧美一级片免费看| 有码一区二区三区| 色综合色综合色综合| 日本一区二区三区dvd视频在线| 国产香蕉久久精品综合网| 日韩av一区二区三区四区| 欧美美女bb生活片| 亚洲国产裸拍裸体视频在线观看乱了 | 国产成人一级电影| 精品久久一二三区| 久久99国产精品尤物| 日韩美女天天操| 麻豆成人久久精品二区三区红| 国产成人8x视频一区二区| 精品国产凹凸成av人导航| 中文欧美字幕免费| eeuss国产一区二区三区| 中文字幕在线不卡一区二区三区| 亚洲成人资源在线| 欧美乱妇一区二区三区不卡视频| 国产日产欧美一区二区视频| 夜夜亚洲天天久久| 欧美日韩精品欧美日韩精品一| 久久久午夜电影| 成人午夜激情视频| 自拍偷自拍亚洲精品播放| 色一区在线观看| 视频一区在线播放| 99久久伊人网影院| 日韩欧美在线影院| 亚洲美女区一区| 欧美精选在线播放| 国内精品久久久久影院色| 欧美日韩一二区| 精品一区二区av| 国产精品免费网站在线观看| 在线观看亚洲专区| 捆绑调教一区二区三区| 中文字幕欧美国产| 在线播放91灌醉迷j高跟美女| 亚洲视频免费看| 777午夜精品免费视频| 国产精品一区2区| 亚洲综合久久av| 97国产一区二区| 国产亚洲人成网站| 欧美综合亚洲图片综合区| 九一九一国产精品| 日韩欧美一区在线| 日韩精品成人一区二区三区| 久久亚洲一区二区三区明星换脸 | 丝袜美腿亚洲一区| 久久久久国产精品麻豆ai换脸| 日韩**一区毛片| 制服丝袜成人动漫| 男女性色大片免费观看一区二区| 欧美最猛黑人xxxxx猛交| 免费观看久久久4p| 亚洲伦在线观看| 一本色道久久综合亚洲91| 久久国产精品99精品国产| 欧美夫妻性生活| 色网站国产精品| 亚洲一区二区欧美日韩| 国产婷婷精品av在线| 欧美女孩性生活视频| 色婷婷综合久久久中文字幕| 激情成人综合网| 美美哒免费高清在线观看视频一区二区| 欧美日韩一卡二卡三卡| 92国产精品观看| 天堂av在线一区| 夜夜揉揉日日人人青青一国产精品| 91麻豆福利精品推荐| 亚洲一二三四区| 日韩免费看的电影| 欧美三级中文字幕在线观看| av午夜一区麻豆| www.成人网.com| 99久久亚洲一区二区三区青草| 亚洲一区在线免费观看| 亚洲天堂2014| 亚洲男人的天堂av| 一区2区3区在线看| 亚洲成年人网站在线观看| 亚洲成精国产精品女| 亚洲国产精品久久人人爱蜜臀| 久久伊人中文字幕| 久久久精品黄色| 欧美激情资源网| 91麻豆精品91久久久久久清纯| 国产高清精品网站| 粉嫩一区二区三区在线看| 亚洲一区二区三区美女| 天天综合色天天综合色h| 日韩成人午夜精品| 另类小说欧美激情| 高清视频一区二区| 色婷婷av一区二区三区之一色屋| 久久99精品久久久| 亚洲午夜久久久久久久久电影院| 久久久久久久久久久久电影| 欧亚洲嫩模精品一区三区| 欧美精品日韩一本| 久久久久青草大香线综合精品| 欧美日韩精品欧美日韩精品一 | 日韩毛片视频在线看| 一级日本不卡的影视| 日本va欧美va精品发布| 国产一区二区三区四区五区美女 | 亚洲一区在线免费观看| 丝袜美腿亚洲一区二区图片| 国产乱码精品一区二区三区av | 国产欧美一区二区精品婷婷| 国产性色一区二区| 亚洲一区二区三区中文字幕| 裸体在线国模精品偷拍| 99久久精品国产一区| 日韩一区二区三区三四区视频在线观看 | 欧美精品一区二区三区一线天视频 | 精品国产乱码久久久久久浪潮| 欧美影片第一页| 久久奇米777| 天天综合网 天天综合色| 丁香网亚洲国际| 欧美高清dvd| 亚洲色图.com| 一区二区三区在线播放| 久久精品久久综合| 久久成人免费网| 久久国产麻豆精品| 国产一区二区福利| 欧美视频完全免费看| 国产精品毛片高清在线完整版| 国产精品久久一卡二卡|