Yansıma
Yansıma, çalışma zamanında dilin kendi yapısını kontrol etmeye yarayan bir mekanizmadır. Bazı sorunlara esnek bir şekilde yanıt vermemizi sağlar. Ancak beraberinde getirdiği dezavantajlar da açıktır. Örneğin performans sorunları vb. Go'da, yansıma interface{} ile yakından ilişkilidir. Büyük ölçüde, interface{}'nin göründüğü her yerde yansıma vardır. Go'daki yansıma API'leri standart kütüphane reflect paketi tarafından sağlanır.
Arayüz
Başlamadan önce runtime paketindeki iki arayüzü kısaca anlayalım. Go'da, arayüzler yapı taşlarıdır. Go çalışma zamanında arayüzleri iki büyük kategoriye ayırır. Birincisi metot kümesi olmayan arayüzler, diğeri metot kümesi olan arayüzlerdir. Metot kümesi içeren arayüzler için, çalışma zamanında aşağıdaki yapı iface tarafından temsil edilir
type iface struct {
tab *itab // Veri türü, arayüz türü, metot kümesi vb. içerir
data unsafe.Pointer // Değere işaret eden işaretçi
}Metot kümesi olmayan arayüzler için, çalışma zamanında eface yapısı tarafından temsil edilir. Aşağıdaki gibi
type eface struct {
_type *_type // Tür
data unsafe.Pointer // Değere işaret eden işaretçi
}Bu iki yapı reflect paketi altında onlara karşılık gelen yapı türlerine sahiptir. iface, nonEmptyInterface'e karşılık gelir
type nonEmptyInterface struct {
itab *struct {
ityp *rtype // Statik arayüz türü
typ *rtype // Dinamik somut tür
hash uint32 // Tür hash
_ [4]byte
fun [100000]unsafe.Pointer // Metot kümesi
}
word unsafe.Pointer // Değere işaret eden işaretçi
}eface ise emptyInterface'e karşılık gelir
type emptyInterface struct {
typ *rtype // Dinamik somut tür
word unsafe.Pointer // İşaretçiye sahip değer
}Bu iki tür için, resmi çok net bir tanım vermiştir:
nonEmptyInterface: nonEmptyInterface is the header for an interface value with methodsemptyInterface: emptyInterface is the header for an interface{} value
Yukarıda dinamik somut tür terimi anıldı. Orijinal metin dynamic concrete type şeklindedir. İlk olarak Go dili yüzde yüz statik tür dilidir. Statik kelime dışa dönük soyut arayüz türünün değişmez olduğunu gösterir. Dinamik ise altta saklanan somut uygulamanın türünün değişebileceğini gösterir. Bu noktaya kadar, arayüzün basit prensibi için yansıma öğrenimini karşılamak için bu kadarı yeterlidir.
Köprü
reflect paketi altında, Go'daki türleri temsil etmek için reflect.Type arayüz türü ve Go'daki değerleri temsil etmek için reflect.Value yapı türü bulunur
type Type interface {
...
Name() string
PkgPath() string
Size() uintptr
String() string
Kind() Kind
...
}
type Value struct {
typ *rtype
ptr unsafe.Pointer
flag
}Yukarıdaki kod birçok detayı atlar. Şimdilik sadece bu iki türün varlığını anlayın. Go'daki tüm yansıma ile ilgili işlemler bu iki türe dayanır. reflect paketi, Go'daki türleri yukarıdaki iki türe dönüştürmek için iki fonksiyon sağlar. Böylece yansıma işlemleri yapılabilir. Bunlar sırasıyla reflect.TypeOf fonksiyonu
func TypeOf(i any) Typeve reflect.ValueOf fonksiyonu
func ValueOf(i any) ValueHer iki fonksiyonun parametre türünün any yani interface{}'nin takma adı olduğu görülebilir. Yansıma işlemleri yapmak istiyorsanız, önce türünüzü interface{}'ye dönüştürmeniz gerekir. Bu da neden前面'de yansıma varsa boş arayüzün olduğu söylenmesinin nedenidir. Tam olarak söylenemese de, boş arayüz Go tür sistemi ile yansıma arasındaki köprüdür. Aşağıdaki resim bu süreci canlı bir şekilde betimler.

::: ipucu
Aşağıdaki metinde kolaylık sağlamak için, interface{} yerine takma ad any kullanılacaktır.
:::
Çekirdek
Go'da üç klasik yansıma yasası vardır. Yukarıda anlatılanlarla birleştirildiğinde anlaşılması çok kolaydır. Sırasıyla aşağıdaki gibidir:
Yansıma,
interface{}türü değişkeni yansıma nesnesine dönüştürebilirYansıma, yansıma nesnesini
interface{}türü değişkene geri döndürebilirYansıma nesnesini değiştirmek için, değerin ayarlanabilir olması gerekir
Bu üç yasa Go yansımasının çekirdeğidir. Tür ile ilgili bilgilere erişmek gerektiğinde, reflect.TypeOf kullanılır. Yansıma değerini değiştirmek gerektiğinde, reflect.ValueOf kullanılır.
Tür
reflect.Type, Go'daki türü temsil eder. reflect.TypeOf() fonksiyonu kullanılarak değişken reflect.Type'a dönüştürülebilir. Kod örneği aşağıdaki gibidir
func main() {
str := "hello world!"
reflectType := reflect.TypeOf(str)
fmt.Println(reflectType)
}Çıktı sonucu
stringKind
Type için, Go içsel olarak Go'daki temel türleri temsil etmek için reflect.Kind kullanır. Temelde işaretsiz tamsayı uint'tür.
type Kind uintreflect paketi Kind kullanarak Go'daki tüm temel türleri numaralandırır. Aşağıda gösterildiği gibi
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Pointer
Slice
String
Struct
UnsafePointer
)Kind türü sadece Stringer arayüzünün String() metodunu uygular. Bu türün sadece bu tek metodu vardır. String() metodunun dönüş değeri içsel bir slice'dan gelir. Aşağıda gösterildiği gibi. Bu yazım ilk bakışta map gibi görünür. Ancak aslında bu Go'daki özel bir yazımdır: indeks ifadeleri slice literal'lerinde (index expressions in slice literals)
var kindNames = []string{
Invalid: "invalid",
Bool: "bool",
Int: "int",
Int8: "int8",
Int16: "int16",
Int32: "int32",
Int64: "int64",
Uint: "uint",
Uint8: "uint8",
Uint16: "uint16",
Uint32: "uint32",
Uint64: "uint64",
Uintptr: "uintptr",
Float32: "float32",
Float64: "float64",
Complex64: "complex64",
Complex128: "complex128",
Array: "array",
Chan: "chan",
Func: "func",
Interface: "interface",
Map: "map",
Pointer: "ptr",
Slice: "slice",
String: "string",
Struct: "struct",
UnsafePointer: "unsafe.Pointer",
}type Type interface{
Kind() Kind
}Kind aracılığıyla, boş arayüzün sakladığı değerin hangi temel tür olduğunu bilebiliriz. Örneğin
func main() {
// any türünde bir değişken bildir
var eface any
// Değer ata
eface = 100
// Kind metodu aracılığıyla türünü al
fmt.Println(reflect.TypeOf(eface).Kind())
}Çıktı sonucu
intElem
type Type interface{
Elem() Type
}Type.Elem() metodu kullanılarak, any türündeki veri yapısının sakladığı element türü belirlenebilir. Kabul edilebilen alt parametre türlerinden biri işaretçi, slice, dizi, kanal, harita olmalıdır. Aksi takdirde panic oluşur. Aşağıda kod örneği bulunmaktadır
func main() {
var eface any
eface = map[string]int{}
rType := reflect.TypeOf(eface)
// key() map'in anahtar yansıma türünü döndürür
fmt.Println(rType.Key().Kind())
fmt.Println(rType.Elem().Kind())
}Çıktı
string
intİşaretçi de bir kapsayıcı olarak anlaşılabilir. İşaretçi için Elem() kullanıldığında, işaret ettiği elementin yansıma türü alınır. Kod örneği aşağıdaki gibidir
func main() {
var eface any
// İşaretçi ata
eface = new(strings.Builder)
rType := reflect.TypeOf(eface)
// İşaretçinin işaret ettiği elementin yansıma türünü al
vType := rType.Elem()
// Paket yolunu yazdır
fmt.Println(vType.PkgPath())
// Adını yazdır
fmt.Println(vType.Name())
}strings
BuilderDizi, slice, kanal için kullanım benzerdir.
Size
type Type interface{
Size() uintptr
}Size metodu aracılığıyla ilgili türün kapladığı byte boyutu alınabilir. Örnek aşağıdaki gibidir
func main() {
fmt.Println(reflect.TypeOf(0).Size())
fmt.Println(reflect.TypeOf("").Size())
fmt.Println(reflect.TypeOf(complex(0, 0)).Size())
fmt.Println(reflect.TypeOf(0.1).Size())
fmt.Println(reflect.TypeOf([]string{}).Size())
}Çıktı sonucu
8
16
16
8
24::: ipucu
unsafe.Sizeof() kullanarak aynı etkiyi elde edebilirsiniz.
:::
Comparable
type Type interface{
Comparable() bool
}Comparable metodu aracılığıyla bir türün karşılaştırılabilir olup olmadığı belirlenebilir. Örnek aşağıdaki gibidir
func main() {
fmt.Println(reflect.TypeOf("hello world!").Comparable())
fmt.Println(reflect.TypeOf(1024).Comparable())
fmt.Println(reflect.TypeOf([]int{}).Comparable())
fmt.Println(reflect.TypeOf(struct{}{}).Comparable())
}Çıktı aşağıdaki gibidir
true
true
false
trueImplements
type Type interface{
Implements(u Type) bool
}Implements metodu aracılığıyla bir türün belirli bir arayüzü uygulayıp uygulamadığı belirlenebilir
type MyInterface interface {
My() string
}
type MyStruct struct {
}
func (m MyStruct) My() string {
return "my"
}
type HisStruct struct {
}
func (h HisStruct) String() string {
return "his"
}
func main() {
rIface := reflect.TypeOf(new(MyInterface)).Elem()
fmt.Println(reflect.TypeOf(new(MyStruct)).Elem().Implements(rIface))
fmt.Println(reflect.TypeOf(new(HisStruct)).Elem().Implements(rIface))
}Çıktı sonucu
true
falseConvertibleTo
type Type interface{
ConvertibleTo(u Type) bool
}ConvertibleTo metodu kullanılarak bir türün başka bir belirtilen türe dönüştürülüp dönüştürülemeyeceği belirlenebilir
type MyInterface interface {
My() string
}
type MyStruct struct {
}
func (m MyStruct) My() string {
return "my"
}
type HisStruct struct {
}
func (h HisStruct) String() string {
return "his"
}
func main() {
rIface := reflect.TypeOf(new(MyInterface)).Elem()
fmt.Println(reflect.TypeOf(new(MyStruct)).Elem().ConvertibleTo(rIface))
fmt.Println(reflect.TypeOf(new(HisStruct)).Elem().ConvertibleTo(rIface))
}Çıktı
true
falseDeğer
reflect.Value, yansıma arayüzünün değerini temsil eder. reflect.ValueOf() fonksiyonu kullanılarak değişken reflect.Value'a dönüştürülebilir. Kod örneği aşağıdaki gibidir
func main() {
str := "hello world!"
reflectValue := reflect.ValueOf(str)
fmt.Println(reflectValue)
}Çıktı sonucu
hello world!Type
func (v Value) Type() TypeType metodu bir yansıma değerinin türünü alabilir
func main() {
num := 114514
rValue := reflect.ValueOf(num)
fmt.Println(rValue.Type())
}Çıktı
intElem
func (v Value) Elem() ValueBir yansıma değerinin element yansıma değerini alır
func main() {
num := new(int)
*num = 114514
// İşaretçi örneği
rValue := reflect.ValueOf(num).Elem()
fmt.Println(rValue.Interface())
}Çıktı
114514İşaretçi
Bir yansıma değerinin işaretçisini almanın iki yolu vardır
// v'nin adresini temsil eden bir işaretçi yansıma değeri döndürür
func (v Value) Addr() Value
// v'nin orijinal değerine işaret eden bir uintptr döndürür. uintptr(Value.Addr().UnsafePointer()) ile eşdeğerdir
func (v Value) UnsafeAddr() uintptr
// v'nin orijinal değerine işaret eden bir uintptr döndürür
// Sadece v'nin Kind'ı Chan, Func, Map, Pointer, Slice, UnsafePointer olduğunda geçerlidir, aksi takdirde panic oluşur
func (v Value) Pointer() uintptr
// v'nin orijinal değerine işaret eden bir unsafe.Pointer döndürür
// Sadece v'nin Kind'ı Chan, Func, Map, Pointer, Slice, UnsafePointer olduğunda geçerlidir, aksi takdirde panic oluşur
func (v Value) UnsafePointer() unsafe.PointerÖrnek aşağıdaki gibidir
func main() {
num := 1024
ele := reflect.ValueOf(&num).Elem()
fmt.Println("&num", &num)
fmt.Println("Addr", ele.Addr())
fmt.Println("UnsafeAddr", unsafe.Pointer(ele.UnsafeAddr()))
fmt.Println("Pointer", unsafe.Pointer(ele.Addr().Pointer()))
fmt.Println("UnsafePointer", ele.Addr().UnsafePointer())
}Çıktı
&num 0xc0000a6058
Addr 0xc0000a6058
UnsafeAddr 0xc0000a6058
Pointer 0xc0000a6058
UnsafePointer 0xc0000a6058::: ipucu
fmt.Println parametre türünü yansıma ile alır. Eğer reflect.Value türü ise, otomatik olarak Value.Interface() çağırarak orijinal değerini alır.
:::
Bir map ile tekrar deneyelim
func main() {
dic := map[string]int{}
ele := reflect.ValueOf(&dic).Elem()
println(dic)
fmt.Println("Addr", ele.Addr())
fmt.Println("UnsafeAddr", *(*unsafe.Pointer)(unsafe.Pointer(ele.UnsafeAddr())))
fmt.Println("Pointer", unsafe.Pointer(ele.Pointer()))
fmt.Println("UnsafePointer", ele.UnsafePointer())
}Çıktı
0xc00010e4b0
Addr &map[]
UnsafeAddr 0xc00010e4b0
Pointer 0xc00010e4b0
UnsafePointer 0xc00010e4b0Değer Ayarlama
func (v Value) Set(x Value)Yansıma yoluyla yansıma değerini değiştirmek istiyorsanız, değeri alınabilir olmalıdır. Bu durumda element değerini doğrudan değiştirmeye çalışmak yerine, işaretçi aracılığıyla element değerini değiştirmelisiniz.
func main() {
// *int
num := new(int)
*num = 114514
rValue := reflect.ValueOf(num)
// İşaretçinin işaret ettiği elementi al
ele := rValue.Elem()
fmt.Println(ele.Interface())
ele.SetInt(11)
fmt.Println(ele.Interface())
}Çıktı aşağıdaki gibidir
114514
11Değer Alma
func (v Value) Interface() (i any)Interface() metodu aracılığıyla yansıma değerinin orijinal değeri alınabilir
func main() {
var str string
str = "hello"
rValue := reflect.ValueOf(str)
if v, ok := rValue.Interface().(string); ok {
fmt.Println(v)
}
}Çıktı
helloFonksiyon
Yansıma aracılığıyla fonksiyonun tüm bilgileri alınabilir ve fonksiyon yansıma ile çağrılabilir
Bilgi
Yansıma türü aracılığıyla fonksiyonun tüm bilgilerini alın
func Max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
rType := reflect.TypeOf(Max)
// Fonksiyon adını yazdır, literal fonksiyon türünün adı yoktur
fmt.Println(rType.Name())
// Parametre, dönüş değeri sayısını yazdır
fmt.Println(rType.NumIn(), rType.NumOut())
rParamType := rType.In(0)
// İlk parametrenin türünü yazdır
fmt.Println(rParamType.Kind())
rResType := rType.Out(0)
// İlk dönüş değerinin türünü yazdır
fmt.Println(rResType.Kind())
}Çıktı
2 1
int
intÇağrı
Yansıma değeri aracılığıyla fonksiyonu çağır
func (v Value) Call(in []Value) []Valuefunc main() {
// Fonksiyonun yansıma değerini al
rType := reflect.ValueOf(Max)
// Parametre dizisini gir
rResValue := rType.Call([]reflect.Value{reflect.ValueOf(18), reflect.ValueOf(50)})
for _, value := range rResValue {
fmt.Println(value.Interface())
}
}Çıktı
50Yapı
Aşağıdaki yapı varsayılsın
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
money int
}
func (p Person) Talk(msg string) string {
return msg
}Alanlara Erişim
reflect.StructField yapısının yapısı aşağıdaki gibidir
type StructField struct {
// Alan adı
Name string
// Paket adı
PkgPath string
// Tür adı
Type Type
// Tag
Tag StructTag
// Alanın byte ofseti
Offset uintptr
// İndeks
Index []int
// İç içe alan olup olmadığı
Anonymous bool
}Yapı alanına erişmenin iki yolu vardır. Biri indeks aracılığıyla erişim, diğeri ad aracılığıyla erişim.
type Type interface{
Field(i int) StructField
}İndeks aracılığıyla erişim örneği aşağıdaki gibidir
func main() {
rType := reflect.TypeOf(new(Person)).Elem()
// Yapı alanlarının sayısını yazdır
fmt.Println(rType.NumField())
for i := 0; i < rType.NumField(); i++ {
structField := rType.Field(i)
fmt.Println(structField.Index, structField.Name, structField.Type, structField.Offset, structField.IsExported())
}
}Çıktı
4
[0] Name string 0 true
[1] Age int 16 true
[2] Address string 24 true
[3] money int 40 falsetype Type interface{
FieldByName(name string) (StructField, bool)
}Ad aracılığıyla erişim örneği aşağıdaki gibidir
func main() {
rType := reflect.TypeOf(new(Person)).Elem()
// Yapı alanlarının sayısını yazdır
fmt.Println(rType.NumField())
if field, ok := rType.FieldByName("money"); ok {
fmt.Println(field.Name, field.Type, field.IsExported())
}
}Çıktı
4
money int falseAlanı Değiştir
Yapı alan değerini değiştirmek istiyorsanız, bir yapı işaretçisi girmelisiniz. Aşağıda bir alanı değiştiren örnek bulunmaktadır
func main() {
// İşaretçi gir
rValue := reflect.ValueOf(&Person{
Name: "",
Age: 0,
Address: "",
money: 0,
}).Elem()
// Alanı al
name := rValue.FieldByName("Name")
// Alan değerini değiştir
if (name != reflect.Value{}) { // Eğer reflect.Value{} döndürürse, bu alanın mevcut olmadığı anlamına gelir
name.SetString("jack")
}
// Yapıyı yazdır
fmt.Println(rValue.Interface())
}Çıktı
{jack 0 0}Yapı özel alanını değiştirmek için, bazı ek işlemler yapılmalıdır. Aşağıdaki gibi
func main() {
// İşaretçi gir
rValue := reflect.ValueOf(&Person{
Name: "",
Age: 0,
Address: "",
money: 0,
}).Elem()
// Özel bir alan al
money := rValue.FieldByName("money")
// Alan değerini değiştir
if (money != reflect.Value{}) {
// Bu yapıya ait dışa aktarılmamış alana işaret eden işaretçi yansıma değerini oluştur
p := reflect.NewAt(money.Type(), money.Addr().UnsafePointer())
// Bu işaretçinin işaret ettiği elementi al, yani değiştirilecek alan
field := p.Elem()
// Değeri değiştir
field.SetInt(164)
}
// Yapıyı yazdır
fmt.Printf("%+v\n", rValue.Interface())
}Tag'e Erişim
StructField alındıktan sonra, Tag'ine doğrudan erişilebilir
// Eğer mevcut değilse, ok false'dur
func (tag StructTag) Lookup(key string) (value string, ok bool)
// Eğer mevcut değilse, boş string döndürür
func (tag StructTag) Get(key string) stringÖrnek aşağıdaki gibidir
func main() {
rType := reflect.TypeOf(new(Person)).Elem()
name, ok := rType.FieldByName("Name")
if ok {
fmt.Println(name.Tag.Lookup("json"))
fmt.Println(name.Tag.Get("json"))
}
}Çıktı
name true
nameMetotlara Erişim
Metotlara erişim alanlara erişim sürecine benzer. Sadece fonksiyon imzası biraz farklıdır. reflect.Method yapısı aşağıdaki gibidir
type Method struct {
// Metot adı
Name string
// Paket adı
PkgPath string
// Metot türü
Type Type
// Metota karşılık gelen fonksiyon, ilk parametre alıcıdır
Func Value
// İndeks
Index int
}Metot bilgilerine erişim örneği aşağıdaki gibidir
func main() {
// Yapı yansıma türünü al
rType := reflect.TypeOf(new(Person)).Elem()
// Metot sayısını yazdır
fmt.Println(rType.NumMethod())
// Metot bilgilerini yineleyerek yazdır
for i := 0; i < rType.NumMethod(); i++ {
method := rType.Method(i)
fmt.Println(method.Index, method.Name, method.Type, method.IsExported())
}
}Çıktı
1
0 Talk func(main.Person, string) string trueMetot parametreleri ve dönüş değerleri detaylarını almak istiyorsanız, Method.Func aracılığıyla alabilirsiniz. Süreç fonksiyon bilgilerine erişim ile aynıdır. Yukarıdaki kodu biraz değiştirin
func main() {
// Yapı yansıma türünü al
rType := reflect.TypeOf(new(Person)).Elem()
// Metot sayısını yazdır
fmt.Println(rType.NumMethod())
// Metot bilgilerini yineleyerek yazdır
for i := 0; i < rType.NumMethod(); i++ {
method := rType.Method(i)
fmt.Println(method.Index, method.Name, method.Type, method.IsExported())
fmt.Println("Metot parametreleri")
for i := 0; i < method.Func.Type().NumIn(); i++ {
fmt.Println(method.Func.Type().In(i).String())
}
fmt.Println("Metot dönüş değerleri")
for i := 0; i < method.Func.Type().NumOut(); i++ {
fmt.Println(method.Func.Type().Out(i).String())
}
}
}İlk parametrenin main.Person olduğunu görebilirsiniz. Yani alıcı türü
1
0 Talk func(main.Person, string) string true
Metot parametreleri
main.Person
string
Metot dönüş değerleri
stringMetot Çağrısı
Metot çağrısı fonksiyon çağrısı sürecine benzer. Ve alıcıyı manuel olarak girmeniz gerekmez. Örnek aşağıdaki gibidir
func main() {
// Yapı yansıma türünü al
rValue := reflect.ValueOf(new(Person)).Elem()
// Metot sayısını yazdır
fmt.Println(rValue.NumMethod())
// Metot bilgilerini yineleyerek yazdır
talk := rValue.MethodByName("Talk")
if (talk != reflect.Value{}) {
// Metodu çağır ve dönüş değerini al
res := talk.Call([]reflect.Value{reflect.ValueOf("hello,reflect!")})
// Dönüş değerlerini yineleyerek yazdır
for _, re := range res {
fmt.Println(re.Interface())
}
}
}Çıktı
1
hello,reflect!Oluşturma
Yansıma aracılığıyla yeni değerler oluşturulabilir. reflect paketi aynı zamanda bazı özel türler için daha uygun fonksiyonlar sağlar.
Temel Türler
// Yansıma değerine işaret eden işaretçi yansıma değerini döndürür
func New(typ Type) Valuestring örneği ile
func main() {
rValue := reflect.New(reflect.TypeOf(*new(string)))
rValue.Elem().SetString("hello world!")
fmt.Println(rValue.Elem().Interface())
}hello world!Yapı
Yapı oluşturma da reflect.New fonksiyonunu kullanır
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address string `json:"address"`
money int
}
func (p Person) Talk(msg string) string {
return msg
}
func main() {
// Yapı yansıma değerini oluştur
rType := reflect.TypeOf(new(Person)).Elem()
person := reflect.New(rType).Elem()
fmt.Println(person.Interface())
}Çıktı
{ 0 0}Slice
Yansıma ile slice oluşturma
func MakeSlice(typ Type, len, cap int) Valuefunc main() {
// Slice yansıma değerini oluştur
rValue := reflect.MakeSlice(reflect.TypeOf(*new([]int)), 10, 10)
// Yineleyerek değer ata
for i := 0; i < 10; i++ {
rValue.Index(i).SetInt(int64(i))
}
fmt.Println(rValue.Interface())
}[0 1 2 3 4 5 6 7 8 9]Map
Yansıma ile Map oluşturma
func MakeMapWithSize(typ Type, n int) Valuefunc main() {
// Map yansıma değerini oluştur
rValue := reflect.MakeMapWithSize(reflect.TypeOf(*new(map[string]int)), 10)
// Değeri ayarla
rValue.SetMapIndex(reflect.ValueOf("a"), reflect.ValueOf(1))
fmt.Println(rValue.Interface())
}map[a:1]Kanal
Yansıma ile kanal oluşturma
func MakeChan(typ Type, buffer int) Valuefunc main() {
// Kanal yansıma değerini oluştur
makeChan := reflect.MakeChan(reflect.TypeOf(new(chan int)).Elem(), 0)
fmt.Println(makeChan.Interface())
}Fonksiyon
Yansıma ile fonksiyon oluşturma
func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Valuefunc main() {
// Paket türünü ve fonksiyon gövdesini gir
fn := reflect.MakeFunc(reflect.TypeOf(new(func(int))).Elem(), func(args []reflect.Value) (results []reflect.Value) {
for _, arg := range args {
fmt.Println(arg.Interface())
}
return nil
})
fmt.Println(fn.Type())
fn.Call([]reflect.Value{reflect.ValueOf(1024)})
}Çıktı
func(int)
1024Tamamen Eşit
reflect.DeepEqual, yansıma paketi tarafından sağlanan iki değişkenin tamamen eşit olup olmadığını belirlemek için kullanılan bir fonksiyondur. İmza aşağıdaki gibidir.
func DeepEqual(x, y any) boolBu fonksiyon her bir temel tür için işlem yapar. Aşağıda bazı türlerin yargılama yöntemleri bulunmaktadır.
- Dizi: Dizideki her element tamamen eşittir
- Slice: Her ikisi
nilolduğunda, tamamen eşit olarak yargılanır. Veya her ikisi boş değilse, uzunluk范围内的 elementler tamamen eşittir - Yapı: Tüm alanlar tamamen eşittir
- Harita: Her ikisi
nilolduğunda, tamamen eşittir. Her ikisinildeğilse, her anahtarın eşlediği değer tamamen eşittir - İşaretçi: Aynı elementi işaret eder veya işaret edilen elementler tamamen eşittir
- Arayüz: Arayüzün somut türü tamamen eşit olduğunda
- Fonksiyon: Sadece her ikisi
nilolduğunda tamamen eşittir, aksi takdirde tamamen eşit değildir
Aşağıda bazı örnekler bulunmaktadır:
Slice
func main() {
a := make([]int, 100)
b := make([]int, 100)
fmt.Println(reflect.DeepEqual(a, b))
}Çıktı
trueYapı
func main() {
mike := Person{
Name: "mike",
Age: 39,
Father: nil,
}
jack := Person{
Name: "jack",
Age: 18,
Father: &mike,
}
tom := Person{
Name: "tom",
Age: 18,
Father: &mike,
}
fmt.Println(reflect.DeepEqual(mike, jack))
fmt.Println(reflect.DeepEqual(tom, jack))
fmt.Println(reflect.DeepEqual(jack, jack))
}Çıktı
false
false
true