婷婷综合国产,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{} 的具體值。

上述程序會打印:

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
    欧美日本一区二区三区四区 | 老鸭窝一区二区久久精品| 欧美综合亚洲图片综合区| 亚洲欧美另类图片小说| 欧美色网站导航| 日韩电影一区二区三区| 久久日韩粉嫩一区二区三区| 国产成a人无v码亚洲福利| 国产精品色婷婷久久58| 91免费精品国自产拍在线不卡| 一区二区三区日韩精品视频| 欧美日韩国产一二三| 麻豆一区二区三| 国产精品久久久久久久蜜臀| 欧美写真视频网站| 久久精品久久99精品久久| 国产精品色呦呦| 在线一区二区三区四区五区| 青青草国产精品97视觉盛宴 | 久久先锋影音av| 国产精一区二区三区| 国产精品情趣视频| 欧美午夜免费电影| 国产伦精品一区二区三区免费| 欧美激情在线一区二区三区| 欧美性大战久久久久久久| 美女任你摸久久| 1000部国产精品成人观看| 在线播放日韩导航| 成人一区在线观看| 视频一区二区国产| 国产精品久久综合| 欧美电影免费提供在线观看| 日本高清不卡在线观看| 国产真实乱偷精品视频免| 一卡二卡三卡日韩欧美| 国产欧美一区二区精品仙草咪| 欧美日韩在线精品一区二区三区激情| 九九视频精品免费| 亚洲成人第一页| 国产精品无码永久免费888| 884aa四虎影成人精品一区| 成人国产亚洲欧美成人综合网| 婷婷综合久久一区二区三区| 国产精品国产三级国产aⅴ原创| 欧美精品99久久久**| 91亚洲资源网| 国产麻豆午夜三级精品| 免费在线观看精品| 亚洲国产日日夜夜| 国产精品久久久久影视| 欧美va在线播放| 欧美美女直播网站| 色婷婷综合激情| 成人免费视频国产在线观看| 久久91精品国产91久久小草| 午夜精品一区在线观看| 一区二区三区精品久久久| 国产精品国产三级国产有无不卡 | 中文字幕在线免费不卡| 国产日韩av一区二区| 精品日产卡一卡二卡麻豆| 制服丝袜国产精品| 777奇米四色成人影色区| 色88888久久久久久影院按摩| 波多野结衣在线aⅴ中文字幕不卡| 国产综合成人久久大片91| 免费欧美高清视频| 蜜桃精品在线观看| 日本不卡的三区四区五区| 午夜av一区二区三区| 亚洲国产精品一区二区久久恐怖片 | 欧美日韩一本到| 欧洲精品视频在线观看| 色av一区二区| 欧美性感一类影片在线播放| 欧美日韩一二三区| 一区二区成人在线| 亚洲自拍偷拍麻豆| 午夜精品免费在线观看| 蜜芽一区二区三区| 奇米色一区二区| 国内偷窥港台综合视频在线播放| 国产一区二区三区在线观看免费| 国内精品久久久久影院薰衣草| 国产在线播精品第三| 韩国一区二区视频| 成人丝袜18视频在线观看| 北岛玲一区二区三区四区| 91老司机福利 在线| 欧美伊人精品成人久久综合97| 欧美日韩成人一区二区| 欧美大尺度电影在线| 久久免费精品国产久精品久久久久| 久久只精品国产| 亚洲精品视频一区二区| 亚洲电影中文字幕在线观看| 蜜臀av性久久久久av蜜臀妖精| 国内不卡的二区三区中文字幕 | 老司机精品视频一区二区三区| 久久电影网站中文字幕 | 国产一区二区中文字幕| 99久久99久久精品免费观看| 欧美日韩专区在线| 国产日韩欧美高清| 一区二区日韩av| 轻轻草成人在线| 成人综合婷婷国产精品久久| 欧美日韩三级一区二区| 久久久综合九色合综国产精品| 亚洲欧洲三级电影| 三级精品在线观看| 成人免费视频免费观看| 欧美日韩国产首页| 国产亚洲成aⅴ人片在线观看| 亚洲嫩草精品久久| 狠狠色丁香久久婷婷综| 色国产精品一区在线观看| 精品毛片乱码1区2区3区| 亚洲摸摸操操av| 国产在线播精品第三| 欧美视频中文字幕| 亚洲国产精品激情在线观看| 亚洲成人精品一区二区| 成人免费观看av| 精品成人免费观看| 亚洲一区二区3| 成人美女视频在线观看18| 欧美一区二区三区播放老司机| 中文字幕一区二区三区在线观看| 三级亚洲高清视频| 99精品国产视频| 久久青草国产手机看片福利盒子 | 色系网站成人免费| 国产欧美一区二区三区在线老狼| 视频一区免费在线观看| 色拍拍在线精品视频8848| 欧美国产乱子伦| 韩国av一区二区三区在线观看| 欧美日韩久久不卡| 亚洲精品你懂的| 99精品欧美一区二区三区小说| 国产视频不卡一区| 九九精品视频在线看| 91精品国产综合久久精品app| 亚洲与欧洲av电影| 久久精品一区蜜桃臀影院| 日韩精品高清不卡| 欧美日韩免费在线视频| 一区二区三区四区在线免费观看 | 欧美视频一区在线| 亚洲免费观看高清| 91伊人久久大香线蕉| 最新国产成人在线观看| fc2成人免费人成在线观看播放| 337p日本欧洲亚洲大胆精品| 美女视频网站久久| 日韩亚洲欧美高清| 麻豆精品精品国产自在97香蕉| 欧美美女直播网站| 午夜激情一区二区| 欧美日韩精品一区二区在线播放| 亚洲国产精品久久人人爱| 欧美三级电影网站| 日韩和欧美的一区| 欧美另类高清zo欧美| 亚洲国产美国国产综合一区二区| 欧美系列在线观看| 人人精品人人爱| 日韩亚洲国产中文字幕欧美| 日本在线不卡视频一二三区| 欧美一级二级三级乱码| 久久精品99国产国产精| 久久九九99视频| 色综合天天综合网天天看片| 一区二区在线观看视频在线观看| 在线中文字幕一区| 亚洲va欧美va人人爽| 91精品国产综合久久精品图片| 麻豆精品视频在线观看| 国产欧美一区二区精品秋霞影院 | 97精品久久久久中文字幕| 亚洲人xxxx| 9191精品国产综合久久久久久| 精品一区二区三区不卡| 日本一区二区三区视频视频| 99久久99久久免费精品蜜臀| 亚洲第一会所有码转帖| 精品国产乱码久久久久久牛牛| 成人精品视频一区二区三区尤物| 亚洲丝袜精品丝袜在线| 欧美高清www午色夜在线视频| 国产一二精品视频| 亚洲狠狠丁香婷婷综合久久久| 欧美日本一区二区在线观看| 国产福利不卡视频| 亚洲成国产人片在线观看| 久久亚洲一区二区三区明星换脸| 色婷婷国产精品久久包臀 | 成人动漫一区二区三区|