校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > 學習使用Go反射的用法示例

學習使用Go反射的用法示例

熱門標簽:福州鐵通自動外呼系統 長沙ai機器人電銷 廣東語音外呼系統供應商 濮陽自動外呼系統代理 地圖標注測試 智能電銷機器人營銷 澳門防封電銷卡 烏魯木齊人工電銷機器人系統 賺地圖標注的錢犯法嗎

什么是反射

大多數時候,Go中的變量,類型和函數非常簡單直接。當需要一個類型、變量或者是函數時,可以直接定義它們:

type Foo struct {
 A int
 B string
}

var x Foo

func DoSomething(f Foo) {
 fmt.Println(f.A, f.B)
}

但是有時你希望在運行時使用變量的在編寫程序時還不存在的信息。比如你正在嘗試將文件或網絡請求中的數據映射到變量中。或者你想構建一個適用于不同類型的工具。在這種情況下,你需要使用反射。反射使您能夠在運行時檢查類型。它還允許您在運行時檢查,修改和創建變量,函數和結構體。

Go中的反射是基于三個概念構建的:類型,種類和值(Types Kinds Values)。標準庫中的reflect包提供了 Go 反射的實現。

反射變量類型

首先讓我們看一下類型。你可以使用反射來調用函數varType := reflect.TypeOf(var)來獲取變量var的類型。這將返回類型為reflect.Type的變量,該變量具有獲取定義時變量的類型的各種信息的方法集。下面我們來看一下常用的獲取類型信息的方法。

我們要看的第一個方法是Name()。這將返回變量類型的名稱。某些類型(例如切片或指針)沒有名稱,此方法會返回空字符串。

下一個方法,也是我認為第一個真正非常有用的方法是Kind()。Type是由Kind組成的---Kind 是切片,映射,指針,結構,接口,字符串,數組,函數,int或其他某種原始類型的抽象表示。要理解Type和Kind之間的差異可能有些棘手,但是請你以這種方式來思考。如果定義一個名為Foo的結構體,則Kind為struct,類型為Foo。

使用反射時要注意的一件事:反射包中的所有內容都假定你知道自己在做什么,并且如果使用不正確,許多函數和方法調用都會引起 panic。例如,如果你在reflect.Type上調用與當前類型不同的類型關聯的方法,您的代碼將會panic。

如果變量是指針,映射,切片,通道或數組變量,則可以使用varType.Elem()找出指向或包含的值的類型。

如果變量是結構體,則可以使用反射來獲取結構體中的字段數,并從每個字段上獲取reflect.StructField結構體。 reflection.StructField為您提供了字段的名稱,標號,類型和結構體標簽。其中標簽信息對應reflect.StructTag類型的字符串,并且它提供了Get方法用于解析和根據特定key提取標簽信息中的子串。

下面是一個簡單的示例,用于輸出各種變量的類型信息:

type Foo struct {
  A int `tag1:"First Tag" tag2:"Second Tag"`
  B string
}

func main() {
  sl := []int{1, 2, 3}
  greeting := "hello"
  greetingPtr := greeting
  f := Foo{A: 10, B: "Salutations"}
  fp := f

  slType := reflect.TypeOf(sl)
  gType := reflect.TypeOf(greeting)
  grpType := reflect.TypeOf(greetingPtr)
  fType := reflect.TypeOf(f)
  fpType := reflect.TypeOf(fp)

  examiner(slType, 0)
  examiner(gType, 0)
  examiner(grpType, 0)
  examiner(fType, 0)
  examiner(fpType, 0)
}

func examiner(t reflect.Type, depth int) {
  fmt.Println(strings.Repeat("\t", depth), "Type is", t.Name(), "and kind is", t.Kind())
  switch t.Kind() {
  case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
    fmt.Println(strings.Repeat("\t", depth+1), "Contained type:")
    examiner(t.Elem(), depth+1)
  case reflect.Struct:
    for i := 0; i  t.NumField(); i++ {
      f := t.Field(i)
      fmt.Println(strings.Repeat("\t", depth+1), "Field", i+1, "name is", f.Name, "type is", f.Type.Name(), "and kind is", f.Type.Kind())
      if f.Tag != "" {
        fmt.Println(strings.Repeat("\t", depth+2), "Tag is", f.Tag)
        fmt.Println(strings.Repeat("\t", depth+2), "tag1 is", f.Tag.Get("tag1"), "tag2 is", f.Tag.Get("tag2"))
      }
    }
  }
}

變量的類型輸出如下:

Type is and kind is slice
   Contained type:
   Type is int and kind is int
 Type is string and kind is string
 Type is and kind is ptr
   Contained type:
   Type is string and kind is string
 Type is Foo and kind is struct
   Field 1 name is A type is int and kind is int
     Tag is tag1:"First Tag" tag2:"Second Tag"
     tag1 is First Tag tag2 is Second Tag
   Field 2 name is B type is string and kind is string
 Type is and kind is ptr
   Contained type:
   Type is Foo and kind is struct
     Field 1 name is A type is int and kind is int
       Tag is tag1:"First Tag" tag2:"Second Tag"
       tag1 is First Tag tag2 is Second Tag
     Field 2 name is B type is string and kind is string

Run in go playground: https://play.golang.org/p/lZ97yAUHxX

使用反射創建新實例

除了檢查變量的類型外,還可以使用反射來讀取,設置或創建值。首先,需要使用refVal := reflect.ValueOf(var) 為變量創建一個reflect.Value實例。如果希望能夠使用反射來修改值,則必須使用refPtrVal := reflect.ValueOf(&var);獲得指向變量的指針。如果不這樣做,則可以使用反射來讀取該值,但不能對其進行修改。

一旦有了reflect.Value實例就可以使用Type()方法獲取變量的reflect.Type。

如果要修改值,請記住它必須是一個指針,并且必須首先對其進行解引用。使用refPtrVal.Elem().Set(newRefVal)來修改值,并且傳遞給Set()的值也必須是reflect.Value。

如果要創建一個新值,可以使用函數newPtrVal := reflect.New(varType)來實現,并傳入一個reflect.Type。這將返回一個指針值,然后可以像上面那樣使用Elem().Set()對其進行修改。

最后,你可以通過調用Interface()方法從reflect.Value回到普通變量值。由于Go沒有泛型,因此變量的原始類型會丟失;該方法返回類型為interface{}的值。如果創建了一個指針以便可以修改該值,則需要使用Elem().Interface()解引用反射的指針。在這兩種情況下,都需要將空接口轉換為實際類型才能使用它。

下面的代碼來演示這些概念:

type Foo struct {
  A int `tag1:"First Tag" tag2:"Second Tag"`
  B string
}

func main() {
  greeting := "hello"
  f := Foo{A: 10, B: "Salutations"}

  gVal := reflect.ValueOf(greeting)
  // not a pointer so all we can do is read it
  fmt.Println(gVal.Interface())

  gpVal := reflect.ValueOf(greeting)
  // it's a pointer, so we can change it, and it changes the underlying variable
  gpVal.Elem().SetString("goodbye")
  fmt.Println(greeting)

  fType := reflect.TypeOf(f)
  fVal := reflect.New(fType)
  fVal.Elem().Field(0).SetInt(20)
  fVal.Elem().Field(1).SetString("Greetings")
  f2 := fVal.Elem().Interface().(Foo)
  fmt.Printf("%+v, %d, %s\n", f2, f2.A, f2.B)
}

他們的輸出如下:

hello
goodbye
{A:20 B:Greetings}, 20, Greetings

Run in go playground https://play.golang.org/p/PFcEYfZqZ8

反射創建引用類型的實例

除了生成內置類型和用戶定義類型的實例之外,還可以使用反射來生成通常需要make函數的實例??梢允褂胷eflect.MakeSlice,reflect.MakeMap和reflect.MakeChan函數制作切片,Map或通道。在所有情況下,都提供一個reflect.Type,然后獲取一個reflect.Value,可以使用反射對其進行操作,或者可以將其分配回一個標準變量。

func main() {
 // 定義變量
  intSlice := make([]int, 0)
  mapStringInt := make(map[string]int)

 // 獲取變量的 reflect.Type
  sliceType := reflect.TypeOf(intSlice)
  mapType := reflect.TypeOf(mapStringInt)

  // 使用反射創建類型的新實例
  intSliceReflect := reflect.MakeSlice(sliceType, 0, 0)
  mapReflect := reflect.MakeMap(mapType)

  // 將創建的新實例分配回一個標準變量
  v := 10
  rv := reflect.ValueOf(v)
  intSliceReflect = reflect.Append(intSliceReflect, rv)
  intSlice2 := intSliceReflect.Interface().([]int)
  fmt.Println(intSlice2)

  k := "hello"
  rk := reflect.ValueOf(k)
  mapReflect.SetMapIndex(rk, rv)
  mapStringInt2 := mapReflect.Interface().(map[string]int)
  fmt.Println(mapStringInt2)
}

使用反射創建函數

反射不僅僅可以為存儲數據創造新的地方。還可以使用reflect.MakeFunc函數使用reflect來創建新函數。該函數期望我們要創建的函數的reflect.Type,以及一個閉包,其輸入參數為[]reflect.Value類型,其返回類型也為[] reflect.Value類型。下面是一個簡單的示例,它為傳遞給它的任何函數創建一個定時包裝器:

func MakeTimedFunction(f interface{}) interface{} {
  rf := reflect.TypeOf(f)
  if rf.Kind() != reflect.Func {
    panic("expects a function")
  }
  vf := reflect.ValueOf(f)
  wrapperF := reflect.MakeFunc(rf, func(in []reflect.Value) []reflect.Value {
    start := time.Now()
    out := vf.Call(in)
    end := time.Now()
    fmt.Printf("calling %s took %v\n", runtime.FuncForPC(vf.Pointer()).Name(), end.Sub(start))
    return out
  })
  return wrapperF.Interface()
}

func timeMe() {
  fmt.Println("starting")
  time.Sleep(1 * time.Second)
  fmt.Println("ending")
}

func timeMeToo(a int) int {
  fmt.Println("starting")
  time.Sleep(time.Duration(a) * time.Second)
  result := a * 2
  fmt.Println("ending")
  return result
}

func main() {
  timed := MakeTimedFunction(timeMe).(func())
  timed()
  timedToo := MakeTimedFunction(timeMeToo).(func(int) int)
  fmt.Println(timedToo(2))
}

你可以在goplayground運行代碼https://play.golang.org/p/QZ8ttFZzGx并看到輸出如下:

starting
ending
calling main.timeMe took 1s
starting
ending
calling main.timeMeToo took 2s
4

反射是每個Go開發人員都應了解并學會的強大工具。但是使用他們可以用來做什么呢?在下一篇博客文章中,我將探討現有庫中反射的一些用法,并使用反射來創建一些新的東西。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • golang之反射和斷言的具體使用
  • Go系列教程之反射的用法
  • 詳解Golang利用反射reflect動態調用方法
  • 淺談Go語言中的結構體struct & 接口Interface & 反射
  • Go語言學習筆記之反射用法詳解
  • Go語言中反射的正確使用
  • 談談Go語言的反射三定律
  • go語言通過反射獲取和設置結構體字段值的方法
  • Go語言中使用反射的方法

標簽:廣西 阿克蘇 德州 貴陽 西雙版納 慶陽 調研邀請 太原

巨人網絡通訊聲明:本文標題《學習使用Go反射的用法示例》,本文關鍵詞  學習,使用,反射,的,用法,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《學習使用Go反射的用法示例》相關的同類信息!
  • 本頁收集關于學習使用Go反射的用法示例的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    一区二区三区欧美| 9i在线看片成人免费| 天天色天天爱天天射综合| 18欧美亚洲精品| 亚洲同性同志一二三专区| 中文字幕一区二区三区在线播放| 久久久精品免费观看| 国产欧美日韩另类视频免费观看 | 精品久久99ma| 欧美成人video| 久久婷婷国产综合国色天香| 久久久亚洲综合| 国产日韩一级二级三级| 国产欧美va欧美不卡在线| 日本一区二区三区在线观看| 国产精品乱人伦中文| 亚洲欧美精品午睡沙发| 一区二区欧美在线观看| 五月天中文字幕一区二区| 视频一区国产视频| 国产在线视频精品一区| 国产在线一区二区| 成人黄色在线视频| 欧洲一区二区三区免费视频| 91精品欧美久久久久久动漫| 久久无码av三级| 亚洲欧美怡红院| 午夜一区二区三区在线观看| 精品一区二区三区影院在线午夜| 国产精品一线二线三线| 成人国产精品免费观看视频| 欧洲另类一二三四区| 日韩三级高清在线| 欧美国产精品劲爆| 亚洲国产日韩a在线播放性色| 蜜桃精品在线观看| 成人av先锋影音| 欧美日韩一区二区三区高清| 欧美精品一区二区三区久久久| 国产午夜精品福利| 亚洲已满18点击进入久久| 另类人妖一区二区av| 成人高清av在线| 欧美精品色一区二区三区| 精品福利二区三区| 亚洲乱码国产乱码精品精的特点| 天天综合天天做天天综合| 国产精品综合在线视频| 在线观看欧美精品| 久久尤物电影视频在线观看| 亚洲欧美经典视频| 国产一区二区三区在线看麻豆| 91欧美一区二区| 精品国产乱码久久久久久影片| 日韩美女精品在线| 蜜桃av一区二区在线观看| 一本到不卡精品视频在线观看| 日韩一区二区三区视频在线观看 | 成熟亚洲日本毛茸茸凸凹| 欧美揉bbbbb揉bbbbb| 国产日韩亚洲欧美综合| 日韩国产一区二| av电影在线不卡| 久久品道一品道久久精品| 日日噜噜夜夜狠狠视频欧美人| 成人a级免费电影| 欧美videossexotv100| 依依成人精品视频| 福利一区福利二区| 日韩三级视频中文字幕| 亚洲国产中文字幕| 99精品视频免费在线观看| 久久久久久久久免费| 午夜视频在线观看一区二区| 91丝袜美腿高跟国产极品老师 | 亚洲成av人片一区二区梦乃| 91在线你懂得| 欧美国产禁国产网站cc| 久久 天天综合| 欧美一级一区二区| 亚洲国产精品视频| 99久久精品国产精品久久| 国产欧美日韩麻豆91| 国产呦精品一区二区三区网站| 日韩一区二区免费在线电影| 午夜私人影院久久久久| 91国偷自产一区二区使用方法| 国产精品萝li| 国产乱码精品1区2区3区| 欧美电影免费观看高清完整版在线观看| 亚洲综合色网站| 日本韩国欧美在线| 综合久久给合久久狠狠狠97色| 国产福利一区二区三区视频| 日韩欧美在线观看一区二区三区| 丝袜美腿亚洲一区二区图片| 欧美亚洲国产怡红院影院| 亚洲欧美色综合| 97成人超碰视| 亚洲日本在线看| 一道本成人在线| 亚洲欧美日韩在线不卡| 一本色道a无线码一区v| 《视频一区视频二区| 99精品偷自拍| 一二三区精品视频| 在线免费亚洲电影| 亚洲狠狠爱一区二区三区| 日本韩国欧美国产| 亚洲福利一二三区| 欧美一区二区三区视频| 理论电影国产精品| www久久久久| 成人精品在线视频观看| 亚洲国产精品高清| 91蜜桃网址入口| 亚洲一区在线观看免费观看电影高清| 日本电影亚洲天堂一区| 亚洲va欧美va人人爽午夜| 日韩一区二区三区免费看| 极品销魂美女一区二区三区| 国产午夜一区二区三区| 成人激情文学综合网| 一区二区三区日本| 欧美久久久影院| 久国产精品韩国三级视频| 中文成人综合网| 欧美丝袜丝交足nylons图片| 欧美a一区二区| 国产日韩精品一区二区三区 | 亚洲国产精品二十页| 91免费国产在线| 午夜精品视频一区| 精品国产一区二区三区久久久蜜月| 国产精品小仙女| 亚洲欧美一区二区三区久本道91| 欧美福利视频一区| 国产一区不卡精品| 亚洲免费观看视频| 日韩一区二区三区四区 | 久久精品亚洲国产奇米99| 成人国产在线观看| 亚洲成人1区2区| 久久亚洲一级片| 日本国产一区二区| 国内外成人在线| 亚洲日本护士毛茸茸| 91精品国产综合久久精品图片| 国产在线播放一区三区四| 国产精品盗摄一区二区三区| 欧美精品日韩精品| 国产成人精品三级| 亚洲成a人v欧美综合天堂| 久久亚洲精精品中文字幕早川悠里 | 日韩专区一卡二卡| 欧美极品少妇xxxxⅹ高跟鞋| 在线不卡免费av| www.66久久| 毛片一区二区三区| 亚洲免费观看高清在线观看| 精品国产污污免费网站入口| 91黄色免费版| 国产成人三级在线观看| 亚洲制服欧美中文字幕中文字幕| 国产夜色精品一区二区av| 欧美日韩国产美| 99久久国产综合精品女不卡| 国内外精品视频| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲日本在线视频观看| 久久精品男人天堂av| 欧美一区中文字幕| 日本道色综合久久| 国产69精品久久久久毛片| 秋霞影院一区二区| 亚洲一卡二卡三卡四卡五卡| 国产精品国产三级国产aⅴ中文| 精品人在线二区三区| 欧美性xxxxxxxx| 一本到一区二区三区| 懂色av一区二区夜夜嗨| 九九热在线视频观看这里只有精品| 亚洲1区2区3区视频| 亚洲精品五月天| 亚洲同性同志一二三专区| 欧美国产精品中文字幕| 精品久久一区二区| 欧美一区在线视频| 3d动漫精品啪啪| 欧美日韩免费观看一区二区三区| 色综合天天综合给合国产| 成人免费毛片片v| 成人性视频网站| 国产白丝精品91爽爽久久| 狠狠久久亚洲欧美| 美国一区二区三区在线播放| 日本在线不卡一区| 丝袜美腿亚洲一区| 日本欧洲一区二区| 日韩av中文字幕一区二区三区|