最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語(yǔ)言反射使用及優(yōu)缺點(diǎn)總結(jié)

 更新時(shí)間:2026年01月04日 09:44:45   作者:Zfox_  
反射是一種讓程序在運(yùn)行時(shí)自省(introspect)和修改自身結(jié)構(gòu)和行為的機(jī)制,這篇文章主要介紹了Go語(yǔ)言反射使用及優(yōu)缺點(diǎn)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

一:什么是反射

反射可以認(rèn)為是程序在運(yùn)行時(shí)的一種能力,反射可以在程序運(yùn)行時(shí)訪問(wèn)、檢測(cè)和修改它本身狀態(tài),比如在程序運(yùn)行時(shí)可以檢查變量的類型和值,調(diào)用它們的方法,甚至修改它們的值。使用反射可以增加程序的靈活性,簡(jiǎn)單來(lái)說(shuō),反射就是程序在運(yùn)行時(shí)能夠檢測(cè)自身和修改自身的一種能力。

二:Go 語(yǔ)言反射

對(duì)于很多的高級(jí)語(yǔ)言都實(shí)現(xiàn)了反射,像 Java,Python。在 Go 語(yǔ)言中,反射在 Go 語(yǔ)言內(nèi)置的 reflect 包下實(shí)現(xiàn)。Go 語(yǔ)言中的反射建立在 Go 的類型系統(tǒng)之上,并且與接口密切相關(guān)。通過(guò)前面的學(xué)習(xí)我們知道 Go 語(yǔ)言的空接口包含類型 (Type) 和值 (Value) 兩個(gè)部分,在反射里,也要用到類型 (Type) 和值 (Value)。

reflect 包中定義了 reflect.Type 和 reflect.Value,正好對(duì)應(yīng)我們前面所說(shuō)的Type 和 Value。要注意的是 reflect.Type 是一個(gè)接口而 reflect.Value 是一個(gè)具體的結(jié)構(gòu)體。在 reflect.Type 接口中定義了很多跟類型相關(guān)的方法,而reflect.Value 則是綁定了很多跟值相關(guān)的方法。

reflect.TypeOf()

由于 reflect.Type 是一個(gè)接口,所以只有當(dāng)某個(gè)類型實(shí)現(xiàn)了這個(gè)接口,我們才能獲取到它的類型,同時(shí),在 reflect 包內(nèi),類型描述符是未導(dǎo)出類型,所以我們只能通過(guò) reflect.TypeOf() 方法獲取 reflect.Type 類型的值。

我們首先看一個(gè)例子,看下 reflect.TypeOf() 的常用用法:

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name string
    Age  int
}

func main() {
    var num int64 = 100
    t1 := reflect.TypeOf(num)
    fmt.Println(t1.String())

    st := Student{
       Name: "zhangsan",
       Age:  18,
    }
    t2 := reflect.TypeOf(st)
    fmt.Println(t2.String())
}

運(yùn)行結(jié)果:

int64
main.Student

可以看到對(duì)于基礎(chǔ)類型和 struct 類型通過(guò)調(diào)用 reflect.TypeOf() 都打印出了對(duì)應(yīng)的類型信息。注意 reflect.TypeOf 返回的是一個(gè) reflect.Type 接口類型,我們通過(guò)調(diào)用這個(gè)接口的 String() 方法,得到最終的字符串信息。

在前面學(xué)習(xí) interface 的章節(jié)中,我們知道一個(gè)具體的數(shù)據(jù)類型是可以賦值給一個(gè) interface 類型的,反過(guò)來(lái)則不行,要用到 interface 的斷言。在一個(gè)interface 賦值之后,其實(shí)是對(duì)應(yīng)了兩個(gè)類型,一個(gè)是靜態(tài)類型,就是在程序編譯期就確定的類型,interface 的靜態(tài)類型就是接口 interface,同時(shí)當(dāng) interface 賦值之后,他還有一個(gè)動(dòng)態(tài)類型,就是被賦值的那個(gè)數(shù)據(jù)的具體類型,假設(shè)在上例中,我們將 st 賦值給一個(gè)空 interface,那么這個(gè) interface 的動(dòng)態(tài)類型就是 Student。

對(duì)一個(gè)數(shù)據(jù)對(duì)象進(jìn)行反射操作,其實(shí)是首先將具體對(duì)象類型轉(zhuǎn)化為一個(gè) interface 類型,然后再將 interface 類型轉(zhuǎn)化為 reflect 包下的反射類型,反射類型里的類型信息和值信息其實(shí)就是對(duì)應(yīng)著這個(gè)中間類型 interface 的類型和值。

reflect.TypeOf() 方法獲取的就是這個(gè) interface{} 中的類型部分。

reflect.ValueOf()

同理,reflect.ValueOf() 方法自然就是獲取接口中的值部分,reflect.ValueOf() 的返回值其實(shí)就是一個(gè) reflect.Value 結(jié)構(gòu)體。

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name string
    Age  int
}

func main() {
    var num int64 = 100
    v1 := reflect.ValueOf(num)
    fmt.Println(v1)
    fmt.Println(v1.String())

    st := Student{
       Name: "zhangsan",
       Age:  18,
    }
    v2 := reflect.ValueOf(st)
    fmt.Println(v2)
    fmt.Println(v2.String())
}

運(yùn)行結(jié)果:

100
<int64 Value>
{zhangsan 18}
<main.Student Value>

注意到這里 fmt.Println(v1) 和 fmt.Println(v1.String()) 打印的不一樣,上面說(shuō)了 reflect.ValueOf() 的返回值就是一個(gè) reflect.Value 結(jié)構(gòu),但是 fmt.Println(v1) 卻打印出了具體的值,這是因?yàn)?fmt.Println 的參數(shù)是一個(gè)接口類型,在執(zhí)行過(guò)程中有一些類型轉(zhuǎn)換,對(duì) reflect.Value 結(jié)構(gòu)做了特殊處理。

三:反射使用

值對(duì)象

reflect 包下跟值對(duì)象相關(guān)的常用函數(shù)或方法:

函數(shù)/方法說(shuō)明
reflect.TypeOf()獲取某個(gè)對(duì)象的反射類型實(shí)現(xiàn) (reflect.Type)
reflect.ValueOf()獲取某個(gè)對(duì)象的反射值對(duì)象(reflect.Value)
reflect.Value.NumField()獲取結(jié)構(gòu)體的反射值對(duì)象中的字段個(gè)數(shù),只對(duì)結(jié)構(gòu)體類型有效
reflect.Value.Field(i)獲取結(jié)構(gòu)體的反射值對(duì)象中的第i個(gè)字段,只對(duì)結(jié)構(gòu)體類型有效
reflect.Kind()從反射值對(duì)象中獲取該值的種類
reflect.Value.MapKeys()對(duì) map 的每個(gè)鍵的 reflect.Value 對(duì)象組成的一個(gè)切片
reflect.Value.MapIndex(i)根據(jù)map的某個(gè)鍵的reflect.Value對(duì)象,返回值的reflect.Value對(duì)象
reflect.Value.Len()對(duì)切片或數(shù)組的反射對(duì)象求切片或數(shù)組的長(zhǎng)度
reflect.Value.Index(i)返回切片或數(shù)組第i個(gè)元素的reflect.Value值
reflect.Int()/reflect.Uint()/reflect.String()/reflect.Bool()從反射的值對(duì)象中取出對(duì)應(yīng)值,注意 reflect.Int()/reflect.Uint()方法對(duì)種類做了合并處理,它們只返回相應(yīng)的最大范圍的類型,Int()返回Int64類型,Uint()返回Uint64類型

獲取 struct 反射值

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float64
}

func main() {

    st := Student{
       Name:  "zhangsan",
       Age:   18,
       Score: 95.5,
    }
    v := reflect.ValueOf(st)
    fmt.Printf("the field num of Student is %d\n", v.NumField())
    fmt.Printf("field1 type is %v, value is %s\n", v.Field(0).Type().Name(), v.Field(0).String())
    fmt.Printf("field2 type is %v, value is %d\n", v.Field(1).Type().Name(), v.Field(1).Int())
    fmt.Printf("field2 type is %v, value is %f\n", v.Field(2).Type().Name(), v.Field(2).Float())
}

運(yùn)行結(jié)果:

the field num of Student is 3
field1 type is string, value is zhangsan
field2 type is int, value is 18
field2 type is float64, value is 95.500000

v := reflect.ValueOf(st),v是一個(gè) Student 類型的反射值對(duì)象,通過(guò) v.NumField() 可以得出 Student 類型的字段個(gè)數(shù),然后 v.Field(i).Type().Name() 打印出各個(gè)字段值的類型,v.Field(i) 打印出各個(gè)字段值

注意:NumField() 和 Field() 方法只有原對(duì)象是結(jié)構(gòu)體時(shí)才能調(diào)用,否則會(huì) panic

類型對(duì)象

函數(shù)/方法說(shuō)明
reflect.Type.NumField()獲取結(jié)構(gòu)體的反射類型對(duì)象中的字段個(gè)數(shù),只對(duì)結(jié)構(gòu)體類型有效
reflect.Type.Field(i)獲取結(jié)構(gòu)體的反射類型對(duì)象中的第i個(gè)字段,只對(duì)結(jié)構(gòu)體類型有效
reflect.Type.Elem()根據(jù)指針獲取對(duì)應(yīng)的具體類型
reflect.Type.NumIn()獲取函數(shù)反射類型的參數(shù)個(gè)數(shù)
reflect.Type.In(i)獲取函數(shù)反射類型的第i個(gè)參數(shù)
reflect.Type.NumOut()獲取函數(shù)反射類型的返回值個(gè)數(shù)
reflect.Type.Out(i)獲取函數(shù)反射類型的第i個(gè)返回值
reflect.Type.NumMethod()獲取struct上綁定的方法個(gè)數(shù)
reflect.Type.Method(i)獲取struct上綁定的第i個(gè)方法

struct 反射類型

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float64
}

func main() {
    st := Student{
       Name:  "zhangsan",
       Age:   18,
       Score: 90.5,
    }
    t := reflect.TypeOf(st)
    fmt.Println(t.Name())
    fmt.Println(t.Kind())
    fmt.Println(t.NumField())
    for i := 0; i < t.NumField(); i++ {
       fmt.Printf("field1 name is %s, field1 type is %s\n", t.Field(i).Name, t.Field(i).Type.String())
    }
}

運(yùn)行結(jié)果:

Student
struct
3
field1 name is Name, field1 type is string

通過(guò) reflect.Type 的 Name() 方法可以獲取對(duì)應(yīng)的 Type 類型,Kind() 方法獲取底層的數(shù)據(jù)種類,即 kind,跟 reflect.Value 一樣,reflect.Type 也提供了 NumField() 方法用于獲取結(jié)構(gòu)體對(duì)象中的字段個(gè)數(shù),通過(guò) t.Field(i).Name 可以獲取對(duì)應(yīng)字段的名字。同樣,F(xiàn)ield(i) 和 NumField() 也只能對(duì)結(jié)構(gòu)體反射使用

指針?lè)瓷漕愋?/h4>
package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float64
}

func main() {
    st := &Student{
       Name:  "zhangsan",
       Age:   18,
       Score: 90.5,
    }
    t := reflect.TypeOf(st)

    fmt.Println(t.Kind())
    fmt.Println(t.Elem().Name())     // 這里一定要加Elem(),根據(jù)指針獲取到具體類型后,才能或者具體的type名
    fmt.Println(t.Elem().NumField()) // 這里一定要加Elem(),根據(jù)指針獲取到具體類型后,才能字段個(gè)數(shù)
    for i := 0; i < t.Elem().NumField(); i++ {
       fmt.Printf("field1 name is %s, field1 type is %s\n", t.Elem().Field(i).Name, t.Elem().Field(i).Type.String())
    }

}

運(yùn)行結(jié)果:

ptr
Student
3
field1 name is Name, field1 type is string
field2 name is Age, field2 type is int
field3 name is Score, field3 type is float64

可以看到,跟上面直接獲取struct有一點(diǎn)點(diǎn)小小的區(qū)別,那就是fmt.Println(t.Kind())打印出的是一個(gè)ptr指針類型,而不再是struct類型,正是因?yàn)檫@里是一個(gè)ptr,所以我們不能直接在這個(gè)ptr上調(diào)用.Name()以及其他的.NumField()之類的方法,要根據(jù)ptr的.Elem()獲取到具體類型之后,才能用這些方法,否則程序就回報(bào)panic,這點(diǎn)一定要注意

反射獲取 struct 方法

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float64
}

func (s *Student) GetName() string {
    return s.Name
}

func (s *Student) SetName(name string) {
    s.Name = name
}

func (s *Student) GetAge() int {
    return s.Age
}

func (s *Student) SetAge(age int) {
    s.Age = age
}

func (s *Student) GetScore() float64 {
    return s.Score
}

func (s *Student) SetScore(score float64) {
    s.Score = score
}

func main() {
    st := &Student{
       Name:  "zhangsan",
       Age:   18,
       Score: 90.5,
    }
    t := reflect.TypeOf(st)

    for i := 0; i < t.NumMethod(); i++ {
       m := t.Method(i)
       fmt.Printf("%+v\n", m)
    }
}

運(yùn)行結(jié)果:

{GetName func(*main.Student) string}
{SetName func(*main.Student, string)}
{GetAge func(*main.Student) int}
{SetAge func(*main.Student, int)}
{GetScore func(*main.Student) float64}
{SetScore func(*main.Student, float64)}

  • reflect.Type.NumMethod():返回struct所綁定的的方法個(gè)數(shù)
  • reflect.Type.Method(i):返回第i個(gè)方法的 reflect.Method 對(duì)象

reflect.Method 定義在 src/reflect/type.go 文件:

type Method struct {  
  Name    string // 方法名
  PkgPath string
  Type  Type  // 方法類型(
  Func  Value // 方法值(方法的接收器作為第一個(gè)參數(shù))
  Index int   // 是結(jié)構(gòu)體中的第幾個(gè)方法
}

所以,通過(guò) reflect.Method 對(duì)象,我們可以獲取到 struct 所綁定的對(duì)應(yīng)方法的方法名,方法類型等信息

通過(guò)反射調(diào)用方法

在上一小節(jié)我們知道了 reflect.Type.Method(i) 可以獲取到 struct 所綁定的具體的方法對(duì)象 reflect.Method,通過(guò)這個(gè)對(duì)象,我們不僅可以獲取方法的詳細(xì)信息,還可以動(dòng)態(tài)的調(diào)用方法。

其實(shí)在 reflect.Value 里我們也可以使用 NumMethod()/Method(i) 方法獲取到對(duì)應(yīng)的方法信息,不同的是 reflect.Value.Method(i) 返回的使一個(gè) reflect.Value 對(duì)象,但是同樣可以根據(jù)這個(gè)對(duì)象來(lái)動(dòng)態(tài)調(diào)用方法,只是兩者調(diào)用方法的方式有所區(qū)別

請(qǐng)看具體例子:

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float64
}

func (s *Student) GetName() string {
    return s.Name
}

func (s *Student) SetName(name string) {
    s.Name = name
}

func (s *Student) GetAge() int {
    return s.Age
}

func (s *Student) SetAge(age int) {
    s.Age = age
}

func (s *Student) GetScore() float64 {
    return s.Score
}

func (s *Student) SetScore(score float64) {
    s.Score = score
}

func main() {
    st := &Student{
       Name:  "zhangsan",
       Age:   18,
       Score: 90.5,
    }
    fmt.Printf("st === %+v\n", st)

    t := reflect.TypeOf(st)
    v := reflect.ValueOf(st)

    m1, ok := t.MethodByName("SetName")  // 獲取SetName方法
    fmt.Printf("t get func by name:%t\n", ok)

    argsV1 := make([]reflect.Value, 0)
    argsV1 = append(argsV1, v)
    argsV1 = append(argsV1, reflect.ValueOf("lisi"))
    m1.Func.Call(argsV1)       // 
    fmt.Printf("st === %+v\n", st)

    m2 := v.MethodByName("SetName")    // 獲取SetName方法
    argsV2 := make([]reflect.Value, 0)
    argsV2 = append(argsV2, reflect.ValueOf("wangwu"))
    m2.Call(argsV2)
    fmt.Printf("st === %+v\n", st)
}

運(yùn)行結(jié)果:

st === &{Name:zhangsan Age:18 Score:90.5}
t get func by name:true
st === &{Name:lisi Age:18 Score:90.5}
st === &{Name:wangwu Age:18 Score:90.5}

可以看到通過(guò) reflect.Type.MethodByName() 方法獲取到的reflect.Method對(duì)象和reflect.Value.MethodByName()方法獲取到的reflect.Method獲取到的reflect.Value對(duì)象都可以在程序運(yùn)行時(shí)動(dòng)態(tài)的調(diào)用方法修改結(jié)構(gòu)本身,student的name由zhangsan------>lisi------>wangwu。

但是二者的調(diào)用存在一個(gè)區(qū)別:通過(guò)reflect.Method調(diào)用方法,必須使用Func字段,而且要傳入接收器的reflect.Value作為第一個(gè)參數(shù)

m1.Func.Call(argsV1)

reflect.Value.MethodByName()返回一個(gè)reflect.Value對(duì)象,它不需要接收器的reflect.Value作為第一個(gè)參數(shù),而且直接使用Call()發(fā)起方法調(diào)用:

m2.Call(argsV2)

通過(guò)反射設(shè)置值

package main

import (
	"fmt"
	"reflect"
	"strings"
)

type User struct {
	Name1 string `big:"-"`
	Name2 string
}

func SetStruct(obj any) {
	v := reflect.ValueOf(obj).Elem()
	t := reflect.TypeOf(obj).Elem()
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		bigField := field.Tag.Get("big")
		// 判斷類型是不是字符串
		if field.Type.Kind() != reflect.String {
			continue
		}
		if bigField == "" {
			continue
		}
		// 修改值
		valueFiled := v.Field(i)
		valueFiled.SetString(strings.ToTitle(valueFiled.String()))
	}
}

func main() {
	s := User{Name1: "name1", Name2: "name2"}
	SetStruct(&s)
	fmt.Println(s)
}

四:反射的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 可以提升程序代碼的靈活性,根據(jù)條件在程序運(yùn)行時(shí)靈活的調(diào)用函數(shù),并且修改源代碼結(jié)構(gòu)

缺點(diǎn):

  • 主要是性能影響,反射過(guò)程中會(huì)有大量的內(nèi)存開(kāi)辟和 gc 過(guò)程,導(dǎo)致程序的性能降低

五:共勉

到此這篇關(guān)于Go語(yǔ)言反射使用及優(yōu)缺點(diǎn)總結(jié)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何使用go-acme/lego實(shí)現(xiàn)自動(dòng)簽發(fā)證書(shū)

    詳解如何使用go-acme/lego實(shí)現(xiàn)自動(dòng)簽發(fā)證書(shū)

    這篇文章主要為大家詳細(xì)介紹了如何使用?go-acme/lego?的客戶端或庫(kù)完成證書(shū)的自動(dòng)簽發(fā),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • 一文帶你使用Golang實(shí)現(xiàn)SSH客戶端

    一文帶你使用Golang實(shí)現(xiàn)SSH客戶端

    SSH?全稱為?Secure?Shell,是一種用于安全地遠(yuǎn)程登錄到網(wǎng)絡(luò)上的其他計(jì)算機(jī)的網(wǎng)絡(luò)協(xié)議,本文主要為大家詳細(xì)介紹了如何使用?Golang?實(shí)現(xiàn)?SSH?客戶端,需要的可以參考下
    2023-11-11
  • Golang模擬令牌桶進(jìn)行對(duì)訪問(wèn)的限流方式

    Golang模擬令牌桶進(jìn)行對(duì)訪問(wèn)的限流方式

    這篇文章主要介紹了Golang模擬令牌桶進(jìn)行對(duì)訪問(wèn)的限流方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • 深入理解Golang中指針的用途與技巧

    深入理解Golang中指針的用途與技巧

    在 Go 語(yǔ)言中,指針是一種重要的概念,了解和正確使用指非常關(guān)鍵,因此本文小編就來(lái)和大家講講Golang 中指針的概念與用法,希望對(duì)大家有所幫助
    2023-05-05
  • 詳解在Go語(yǔ)言中如何實(shí)現(xiàn)枚舉類型

    詳解在Go語(yǔ)言中如何實(shí)現(xiàn)枚舉類型

    枚舉類型是一種常用的數(shù)據(jù)類型,用于表示一組有限的、預(yù)定義的、具名的常量值。而在?Go?語(yǔ)言里是沒(méi)有內(nèi)置枚舉類型的,所以本文將介紹如何實(shí)現(xiàn)?“枚舉類型”,需要的可以參考一下
    2023-04-04
  • Go語(yǔ)言讀取txt文檔的操作方法

    Go語(yǔ)言讀取txt文檔的操作方法

    Go語(yǔ)言提供了很多文件操作的支持,在不同場(chǎng)景下,有對(duì)應(yīng)的處理方式,本節(jié)我們來(lái)介紹一下Go語(yǔ)言讀取txt文檔的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2022-01-01
  • GO語(yǔ)言make和new關(guān)鍵字的區(qū)別

    GO語(yǔ)言make和new關(guān)鍵字的區(qū)別

    本篇文章來(lái)介紹一道非常常見(jiàn)的面試題,到底有多常見(jiàn)呢?可能很多面試的開(kāi)場(chǎng)白就是由此開(kāi)始的。那就是?new?和?make?這兩個(gè)內(nèi)置函數(shù)的區(qū)別,希望對(duì)大家有所幫助
    2023-04-04
  • 超全講解Golang中defer關(guān)鍵字的用法

    超全講解Golang中defer關(guān)鍵字的用法

    本文將從一個(gè)資源回收問(wèn)題引入,引出defer關(guān)鍵字,并對(duì)其進(jìn)行基本介紹,從而讓大家對(duì)Go語(yǔ)言中的defer有更深入的了解,需要的小伙伴可以學(xué)習(xí)一下
    2023-05-05
  • golang時(shí)間字符串和時(shí)間戳轉(zhuǎn)換的案例

    golang時(shí)間字符串和時(shí)間戳轉(zhuǎn)換的案例

    這篇文章主要介紹了golang時(shí)間字符串和時(shí)間戳轉(zhuǎn)換的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟

    go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟

    這篇文章主要介紹了go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟,利用生產(chǎn)的隨機(jī)數(shù)采用橢圓加密算法生成公鑰,具體步驟實(shí)例代碼請(qǐng)參考下本文
    2021-05-05

最新評(píng)論

漠河县| 长阳| 织金县| 武强县| 曲阳县| 即墨市| 邵阳市| 都昌县| 潮州市| 屏东市| 天长市| 扎兰屯市| 五河县| 定安县| 南木林县| 湘潭县| 南平市| 竹北市| 炉霍县| 陈巴尔虎旗| 新河县| 苏尼特左旗| 泽普县| 汉川市| 乃东县| 西盟| 沾化县| 昌江| 吴江市| 平顺县| 象山县| 长寿区| 元朗区| 新晃| 浦城县| 临朐县| 太仆寺旗| 九台市| 盐津县| 中西区| 出国|