Golang Reflection

最近的一個(gè)task是要讀取環(huán)境變量中的配置冗栗,于是想到了反射機(jī)制。反射機(jī)制常常能提供更高維度的視野,可以寫出更general的程序恨溜。

"reflect"包下主要是Type和Value兩個(gè)struct:

  • Type封裝了“類型”的屬性垃杖,定義相關(guān)的東西找他男杈;
  • Value主要封裝了“值”的屬性,與值相關(guān)的東西找他沒錯(cuò)调俘。此外伶棒,他是線程安全的(或者叫g(shù)oroutine安全).

Structs for Case

type Class struct {
    Name    string   `json:"name"`
    Student *Student `json:"student"`
    Grade   int      `json:"grade"`
    school  string   `json:"school"`
}

type Student struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

Cycle

反射機(jī)制主要是了解它的整個(gè)cycle,才能玩的轉(zhuǎn)彩库。肤无。。

Object->Reflect->Object

s := Student{Name: "LiLei", Age: 20}

typ := reflect.TypeOf(s)
val := reflect.ValueOf(s)
fmt.Printf("The type is %s.\n", typ.String())
fmt.Printf("The name is %s.\n", val.FieldByName("Name").String())

if s, ok := val.Interface().(Student); ok {
    fmt.Printf("The student is %s.\n", s.Name)
} else {
    fmt.Println("Wrong!")
}

// output:
// The type is main.Student.
// The name is LiLei.
// The student is LiLei.

Type->Object

畢竟golang沒有jvm那種東西骇钦,不能runtime加載宛渐。所以type還是得從hard code得到

t := reflect.TypeOf(Student{})
val := reflect.New(t)
fmt.Println(val.Type().String())

// output
// *main.Student

這里reflect.New(reflect.Type)返回的是指向new出的value的指針。

Reflect Operation

使用反射最主要的還是要能操作對(duì)象啦

Traverse Object

s := &Student{"LiLei", 18}
c := &Class{"Class A", s, 6, "Century Ave"}

val := reflect.ValueOf(c)
typ := reflect.TypeOf(c)
if val.Kind() == reflect.Ptr {
    fmt.Printf("It is a pointer. Address its value.\n")
    val = val.Elem()
    typ = typ.Elem()
}

for i := 0; i < val.NumField(); i = i + 1 {
    fv := val.Field(i)
    ft := typ.Field(i)
    switch fv.Kind() {
    case reflect.String:
        fmt.Printf("The %d th %s types %s valuing %s with tag env %s\n", i, ft.Name, "string", fv.String(), ft.Tag.Get("env"))
    case reflect.Int:
        fmt.Printf("The %d th %s types %s valuing %d with tag env %s\n", i, ft.Name, "int", fv.Int(), ft.Tag.Get("env"))
    case reflect.Ptr:
        fmt.Printf("The %d th %s types %s valuing %v with tag env %s\n", i, ft.Name, "pointer", fv.Pointer(), ft.Tag.Get("env"))
    }
}

// It is a pointer. Address its value.
// The 0 th Name types string valuing Class A with tag env NAME
// The 1 th Student types pointer valuing 826814776864 with tag env STUDENT
// The 2 th Grade types int valuing 6 with tag env GRADE
// The 3 th school types string valuing Century Ave with tag env SCHOOL

這里眯搭,私有的屬性也是能遍歷到值的窥翩。Tag可以為struct附帶很多信息,合理利用可以出奇跡啊鳞仙。

Modify Object

c := &Class{}

val := reflect.ValueOf(c).Elem()
typ := reflect.TypeOf(c).Elem()

for i := 0; i < val.NumField(); i = i + 1 {
    fv := val.Field(i)
    ft := typ.Field(i)
    if !fv.CanSet() {
        fmt.Printf("The %d th %s is unaccessible.\n", i, ft.Name)
        continue
    }

    switch fv.Kind() {
    case reflect.String:
        fv.SetString("LiLei")
    case reflect.Int:
        fv.SetInt(18)
    case reflect.Ptr:
        continue
    }
}

fmt.Printf("%v\n", c)

// output:
// The 3 th school is unaccessible.
// &{LiLei <nil> 18 }

Map/Array/Slice/Channel

Golang的reflect還針對(duì)其他幾個(gè)類型提供了特殊的api寇蚊。

m := map[string]string{
    "a": "A",
    "b": "B",
}

mv := reflect.ValueOf(m)
for _, k := range mv.MapKeys() {
    v := mv.MapIndex(k)
    fmt.Printf("%s - %s\n", k, v)
}

// output:
// a - A
// b - B

其他類型也有對(duì)應(yīng)的api,具體就查doc吧繁扎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末幔荒,一起剝皮案震驚了整個(gè)濱河市糊闽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌爹梁,老刑警劉巖右犹,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異姚垃,居然都是意外死亡念链,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門积糯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掂墓,“玉大人,你說我怎么就攤上這事看成【啵” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵川慌,是天一觀的道長(zhǎng)吃嘿。 經(jīng)常有香客問我,道長(zhǎng)梦重,這世上最難降的妖魔是什么兑燥? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮琴拧,結(jié)果婚禮上降瞳,老公的妹妹穿的比我還像新娘。我一直安慰自己蚓胸,他們只是感情好挣饥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沛膳,像睡著了一般亮靴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上于置,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天茧吊,我揣著相機(jī)與錄音,去河邊找鬼八毯。 笑死搓侄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的话速。 我是一名探鬼主播讶踪,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼泊交!你這毒婦竟也來了乳讥?” 一聲冷哼從身側(cè)響起柱查,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎云石,沒想到半個(gè)月后唉工,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汹忠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年淋硝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宽菜。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谣膳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铅乡,到底是詐尸還是另有隱情继谚,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布阵幸,位于F島的核電站犬庇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏侨嘀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一捂襟、第九天 我趴在偏房一處隱蔽的房頂上張望咬腕。 院中可真熱鬧,春花似錦葬荷、人聲如沸涨共。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽举反。三九已至,卻和暖如春扒吁,著一層夾襖步出監(jiān)牢的瞬間火鼻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工雕崩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魁索,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓盼铁,卻偏偏與公主長(zhǎng)得像粗蔚,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饶火,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容