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

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

Go系列教程之反射的用法

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

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

本教程分為如下小節。

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

讓我們來逐個討論這些章節。

什么是反射?

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

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

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

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

package main

import (
 "fmt"
)

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

在 playground 上運行

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

現在了解一下,需要在運行時求得變量類型的情況。假如我們要編寫一個簡單的函數,它接收結構體作為參數,并用它來創建一個 SQL 插入查詢。

考慮下面的程序:

package main

import (
 "fmt"
)

type order struct {
 ordId  int
 customerId int
}

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

在 playground 上運行

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

insert into order values(1234, 567)

這個函數寫起來很簡單。我們現在編寫這個函數。

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 函數用 o 的兩個字段(ordId 和 customerId),創建了插入查詢。該程序會輸出:

insert into order values(1234, 567)

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

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 函數(上述程序中的第 16 行),它可以接收任何結構體作為參數,根據結構體的字段創建插入查詢。

例如,如果我們傳入下面的結構體:

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

createQuery 函數應該返回:

insert into order values (1234, 567)

類似地,如果我們傳入:

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

該函數會返回:

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

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

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

reflect 包

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

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

reflect.Type 和 reflect.Value

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

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 函數接收 interface{} 作為參數。在第 14 行,reflect.TypeOf 接收了參數 interface{},返回了reflect.Type,它包含了傳入的 interface{} 參數的具體類型。同樣地,在第 15 行,reflect.ValueOf 函數接收參數 interface{},并返回了 reflect.Value,它包含了傳來的 interface{} 的具體值。

上述程序會打?。?/p>

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

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

NumField() 和 Field() 方法

NumField() 方法返回結構體中字段的數量,而 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 方法只能在結構體上使用,我們在第 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 行,我們取出 reflect.Value,并轉換為 int64,而在第 13 行,我們取出 reflect.Value 并將其轉換為 string。該程序會輸出:

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

完整的程序

現在我們已經具備足夠多的知識,來完成我們的查詢生成器了,我們來實現它把。

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 行,我們首先檢查了傳來的參數是否是一個結構體。在第 23 行,我們使用了 Name() 方法,從該結構體的 reflect.Type 獲取了結構體的名字。接下來一行,我們用 t 來創建查詢。

在第 28 行,case 語句 檢查了當前字段是否為 reflect.Int,如果是的話,我們會取到該字段的值,并使用 Int() 方法轉換為 int64。if else 語句用于處理邊界情況。請添加日志來理解為什么需要它。在第 34 行,我們用來相同的邏輯來取到 string。

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

該程序會輸出:

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)

我們應該使用反射嗎?

我們已經展示了反射的實際應用,現在考慮一個很現實的問題。我們應該使用反射嗎?我想引用 Rob Pike 關于使用反射的格言,來回答這個問題。

清晰優于聰明。而反射并不是一目了然的。

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

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

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

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

巨人網絡通訊聲明:本文標題《Go系列教程之反射的用法》,本文關鍵詞  系列,教程,之,反射,的,用法,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go系列教程之反射的用法》相關的同類信息!
  • 本頁收集關于Go系列教程之反射的用法的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    成人性生交大片免费看中文网站| 欧美三级韩国三级日本一级| 色婷婷国产精品综合在线观看| 另类小说欧美激情| 日韩在线一区二区三区| 在线观看视频欧美| 欧美tickling网站挠脚心| 91久久一区二区| 久久久精品免费网站| 亚洲精选一二三| 成人午夜碰碰视频| 高清不卡在线观看| 自拍偷在线精品自拍偷无码专区| 免费人成黄页网站在线一区二区| 欧美丝袜自拍制服另类| 一区二区三区在线播| 92国产精品观看| 国产精品久久久久久久蜜臀 | 亚洲美女视频在线观看| 国产69精品一区二区亚洲孕妇| 一本一本大道香蕉久在线精品| 国产精品久久看| 国产精品白丝jk白祙喷水网站| 欧美一区二区三区免费在线看| 亚洲第一搞黄网站| 无吗不卡中文字幕| 欧美电影一区二区| 91电影在线观看| av中文字幕亚洲| 激情综合一区二区三区| 午夜视频久久久久久| 亚洲日穴在线视频| 国产欧美日韩综合精品一区二区| 日韩一级精品视频在线观看| 欧美视频中文一区二区三区在线观看 | 欧美一二三区在线| 精品视频999| 日精品一区二区三区| 亚洲国产成人av| 日韩av电影天堂| 国产乱码精品1区2区3区| 懂色av一区二区三区蜜臀| 一本到一区二区三区| 欧美日韩在线播| 欧美一区二区三区四区在线观看| 欧美这里有精品| 精品少妇一区二区三区在线视频| 久久综合色鬼综合色| 国产女人18毛片水真多成人如厕| 蜜桃91丨九色丨蝌蚪91桃色| 国产乱人伦偷精品视频免下载| 不卡视频一二三四| 一本久久a久久免费精品不卡| 在线看一区二区| www日韩大片| 最新热久久免费视频| 一区二区三区在线看| 另类的小说在线视频另类成人小视频在线 | 亚洲综合男人的天堂| 久久精品国产77777蜜臀| 99在线精品观看| 91麻豆精品国产91久久久资源速度 | 国产精品亲子伦对白| 日韩福利视频导航| 成+人+亚洲+综合天堂| 欧美一级xxx| 亚洲一区二区中文在线| 国产91精品一区二区麻豆亚洲| 欧美日韩国产欧美日美国产精品| 久久久精品黄色| 青青草97国产精品免费观看| 色婷婷精品久久二区二区蜜臂av | 一本在线高清不卡dvd| 精品欧美黑人一区二区三区| 亚洲美女在线一区| 粉嫩在线一区二区三区视频| 欧美电视剧在线看免费| 首页亚洲欧美制服丝腿| 91国产福利在线| 亚洲免费观看视频| 国产一区二区不卡| 国内成人精品2018免费看| 日本一区二区免费在线| 国产盗摄视频一区二区三区| 樱花影视一区二区| 欧美日韩卡一卡二| 中文字幕 久热精品 视频在线| 色综合色综合色综合色综合色综合| 欧美草草影院在线视频| 日本不卡视频在线| 欧美日韩精品专区| 亚洲一级片在线观看| 91丨porny丨国产| 国产精品美女久久久久久久网站| 国产一区视频网站| 2022国产精品视频| 日本欧美加勒比视频| 69堂精品视频| 亚洲444eee在线观看| 欧美亚洲免费在线一区| 夜夜爽夜夜爽精品视频| 色综合夜色一区| 亚洲一区二区三区四区在线免费观看| 成人精品免费视频| 国产精品美女一区二区三区| 丰满放荡岳乱妇91ww| 中文字幕一区二区三区色视频| 亚洲综合免费观看高清完整版在线 | 久久超碰97中文字幕| 678五月天丁香亚洲综合网| 亚洲国产aⅴ天堂久久| 欧美丝袜第三区| 午夜精品成人在线视频| 欧美美女bb生活片| 免费观看一级特黄欧美大片| 欧美一激情一区二区三区| 狠狠色丁香婷婷综合久久片| 久久精品视频一区二区| 不卡av电影在线播放| 一级日本不卡的影视| 欧美高清激情brazzers| 韩国中文字幕2020精品| 国产日韩欧美麻豆| 色悠悠久久综合| 亚洲国产婷婷综合在线精品| 精品日韩欧美一区二区| 成人18视频在线播放| 亚洲超碰97人人做人人爱| 2023国产精华国产精品| 欧美日韩和欧美的一区二区| 天天色天天操综合| 国产蜜臀97一区二区三区| 色综合天天综合在线视频| 视频一区中文字幕国产| 国产亚洲欧美日韩日本| 欧美性大战xxxxx久久久| 国产成人精品三级| 偷拍与自拍一区| 久久久久久久网| 欧美视频一区二区三区四区 | 人人爽香蕉精品| 国产精品久久久久久久久久久免费看 | 国产精品99精品久久免费| 亚洲卡通动漫在线| 国产日产欧美一区二区视频| 欧美视频一区二区三区四区| 国产福利一区二区三区| 男女视频一区二区| 国产精品对白交换视频| 日韩欧美国产成人一区二区| 国产成人综合网| 蜜臀av性久久久久蜜臀aⅴ| 久久美女高清视频| 51午夜精品国产| 97se亚洲国产综合在线| 免费在线观看一区二区三区| 亚洲男人天堂一区| 欧美日韩aaaaaa| www.视频一区| 狠狠色丁香婷婷综合| 婷婷亚洲久悠悠色悠在线播放| 国产精品成人一区二区艾草| 精品久久久久香蕉网| 日韩欧美一区中文| 91麻豆精品国产91久久久久久 | 久久国产精品露脸对白| 亚洲男同1069视频| 国产精品丝袜在线| 国产亚洲1区2区3区| 日韩欧美资源站| 欧美一卡2卡三卡4卡5免费| 欧美三级在线看| 欧美中文字幕亚洲一区二区va在线 | 久久亚洲二区三区| 日韩欧美美女一区二区三区| 在线不卡中文字幕| 欧美日韩大陆一区二区| 在线观看视频一区二区| www.在线成人| 色综合久久88色综合天天免费| 99国产欧美久久久精品| gogo大胆日本视频一区| 91色porny在线视频| 成人av网站在线观看| 一本色道亚洲精品aⅴ| 国产高清在线观看免费不卡| 激情综合色丁香一区二区| 国产一区二区三区四| 亚洲网友自拍偷拍| 麻豆专区一区二区三区四区五区| 久久精品国产澳门| 国产在线视频精品一区| 成人在线视频一区| 国产一区二区三区在线观看精品| 国产91丝袜在线18| 91小视频免费观看| 欧美日韩综合不卡| 91精品国产色综合久久| 国产亚洲精品aa午夜观看| 夜夜亚洲天天久久|