>  기사  >  백엔드 개발  >  Golang의 반영에 대한 자세한 설명(예)

Golang의 반영에 대한 자세한 설명(예)

藏色散人
藏色散人앞으로
2020-09-08 09:21:233936검색

다음은 golang tutorial 칼럼에 나온 Golang의 반영(예제)에 대한 자세한 설명입니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

Golang의 반영에 대한 자세한 설명(예)

머리말

Reflection은 여러 언어에서 훌륭하게 사용됩니다. 컴퓨터 과학에서 리플렉션은 자기 설명 공격과 자기 제어 공격을 가능하게 하는 응용 프로그램 클래스를 나타냅니다.

이 글은 Golang의 성찰에 대한 저자의 메모를 기록합니다.

10초 후에는 다음 지식 포인트가 가까이에 있을 것입니다.
1. 반사 소개
2.
3. 정확히 리플렉션이 할 수 있는 일

Text

1. 리플렉션 소개

Golang은 컴파일 타임에 유형을 알지 못해도 변수를 업데이트하고 런타임에 값을 볼 수 있는 메커니즘을 제공합니다 , 호출 방법 을 수행하고 레이아웃을 직접 조작하는 것을 반사라고 합니다. 2. 리플렉션을 사용하는 이유는 무엇인가요?

예를 들어 때로는 다양한 유형의 값을 처리할 수 있는 함수가 필요할 때가 있습니다. 유형을 모르고 다음과 같이 쓸 수 있습니다.

// 伪代码
switch value := value.(type) {
case string:
	// ...一些操作
case int:	
	// ...一些操作	
case cbsStruct: // 自定义的结构体	
	// ...一些操作

// ...
}

문제를 발견하셨나요?

여기에

문제
가 있습니다. 유형이 많고, 이 함수를 작성하는 데 시간이 매우 오래 걸리고, 사용자 정의 유형도 있을 수 있습니다. 이는 이 판단이 불가능하기 때문에 향후에 변경되어야 할 수도 있음을 의미합니다. 알 수 없는 값이 어떤 유형에 속하는지 알아보세요. 알 수 없는 유형을 꿰뚫어 볼 수 없는 경우 위 코드는 실제로 그다지 합리적이지 않습니다. 이때 이를 처리하는 데 도움이 되는

Reflection

이 필요합니다. Reflection은 TypeOf 및 ValueOf 함수를 사용하여 해당 유형의 정보를 얻습니다. 인터페이스에서 대상을 지정하고 쉽게 목적을 달성하세요 . 3. 성찰은 정확히 무엇을 할 수 있나요?

1 변수의 내부 정보 가져오기

reflect는 인터페이스 변수의 내용에 액세스하는 두 가지 유형을 제공합니다.

Type reflect.ValueOf()0reflect.TypeOf() nil 코드 출력
Function
입력 받기 매개변수 인터페이스의 데이터 값이 비어 있으면 <- 0
임을 참고하세요. 입력 매개변수 인터페이스가 비어 있으면 <- nil
package main

import (
	"fmt"
	"reflect"
)

func main() {
	var name string = "咖啡色的羊驼"

	// TypeOf会返回目标数据的类型,比如int/float/struct/指针等
	reflectType := reflect.TypeOf(name)

	// valueOf返回目标数据的的值,比如上文的"咖啡色的羊驼"
	reflectValue := reflect.ValueOf(name)

	fmt.Println("type: ", reflectType)
	fmt.Println("value: ", reflectValue)
}

:

type:  string
value:  咖啡色的羊驼

Deeper 레벨: 위 작업이 발생하면 리플렉션이 변환됩니다. "인터페이스 유형의 변수"를 "반영된 인터페이스 유형" 변수"로 변환합니다. 예를 들어 위의 경우 실제로는 Reflect.Value 및 Reflect.Type의 인터페이스 개체를 반환합니다. (IDE에 따라 해당 함수의 반환 유형을 추적하면 알 수 있습니다)

2.구조체 반영

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Id   int
	Name string
}

func (s Student) Hello(){
	fmt.Println("我是一个学生")
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}

	// 获取目标对象
	t := reflect.TypeOf(s)
	// .Name()可以获取去这个类型的名称
	fmt.Println("这个类型的名称是:", t.Name())

	// 获取目标对象的值类型
	v := reflect.ValueOf(s)
	// .NumField()来获取其包含的字段的总数
	for i := 0; i < t.NumField(); i++ {
		// 从0开始获取Student所包含的key
		key := t.Field(i)

		// 通过interface方法来获取key所对应的值
		value := v.Field(i).Interface()

		fmt.Printf("第%d个字段是:%s:%v = %v \n", i+1, key.Name, key.Type, value)
	}

	// 通过.NumMethod()来获取Student里头的方法
	for i:=0;i<t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Printf("第%d个方法是:%s:%v\n", i+1, m.Name, m.Type)
	}
}

출력:
这个类型的名称是: Student
第1个字段是:Id:int = 1 
第2个字段是:Name:string = 咖啡色的羊驼 
第1个方法是:Hello:func(main.Student)

3.익명 또는 임베디드 필드 반영

package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

type People struct {
	Student // 匿名字段
}

func main() {
	p := People{Student{Id: 1, Name: "咖啡色的羊驼"}}

	t := reflect.TypeOf(p)
	// 这里需要加一个#号,可以把struct的详情都给打印出来
	// 会发现有Anonymous:true,说明是匿名字段
	fmt.Printf("%#v\n", t.Field(0))

	// 取出这个学生的名字的详情打印出来
	fmt.Printf("%#v\n", t.FieldByIndex([]int{0, 1}))

	// 获取匿名字段的值的详情
	v := reflect.ValueOf(p)
	fmt.Printf("%#v\n", v.Field(0))
}

출력:
reflect.StructField{Name:"Student", PkgPath:"", Type:(*reflect.rtype)(0x10aade0), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}

reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x109f4e0), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false}

main.Student{Id:1, Name:"咖啡色的羊驼"}

4. 들어오는 유형이 원하는 유형인지 확인

package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}
	t := reflect.TypeOf(s)

	// 通过.Kind()来判断对比的值是否是struct类型
	if k := t.Kind(); k == reflect.Struct {
		fmt.Println("bingo")
	}

	num := 1;
	numType := reflect.TypeOf(num)
	if k := numType.Kind(); k == reflect.Int {
		fmt.Println("bingo")
	}
}

출력:
bingo
bingo

5. 리플렉션을 통해 콘텐츠 수정

package main

import (
	"reflect"
	"fmt"
)

type Student struct {
	Id   int
	Name string
}

func main() {
	s := &Student{Id: 1, Name: "咖啡色的羊驼"}

	v := reflect.ValueOf(s)

	// 修改值必须是指针类型否则不可行
	if v.Kind() != reflect.Ptr {
		fmt.Println("不是指针类型,没法进行修改操作")
		return
	}

	// 获取指针所指向的元素
	v = v.Elem()

	// 获取目标key的Value的封装
	name := v.FieldByName("Name")

	if name.Kind() == reflect.String {
		name.SetString("小学生")
	}

	fmt.Printf("%#v \n", *s)


	// 如果是整型的话
	test := 888
	testV := reflect.ValueOf(&test)
	testV.Elem().SetInt(666)
	fmt.Println(test)
}

출력:
main.Student{Id:1, Name:"小学生"} 
666

6.

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Id   int
	Name string
}

func (s Student) EchoName(name string){
	fmt.Println("我的名字是:", name)
}

func main() {
	s := Student{Id: 1, Name: "咖啡色的羊驼"}

	v := reflect.ValueOf(s)

	// 获取方法控制权
	// 官方解释:返回v的名为name的方法的已绑定(到v的持有值的)状态的函数形式的Value封装
	mv := v.MethodByName("EchoName")
	// 拼凑参数
	args := []reflect.Value{reflect.ValueOf("咖啡色的羊驼")}

	// 调用函数
	mv.Call(args)
}

출력 :
我的名字是: 咖啡色的羊驼

##4. 리플렉션에 대한 몇 가지 소소한 사항

1. 리플렉션을 사용할 때 먼저 연산할 값이 예상되는 유형인지, "할당"할 수 있는지 확인해야 합니다. 그렇지 않으면 Reflect 패키지가 무자비하게 작동하지 않습니다.

2. 리플렉션은 주로 Golang의 인터페이스 유형과 관련이 있습니다. 인터페이스 유형에만 리플렉션이 있습니다. 관심이 있으시면 TypeOf 및 ValueOf를 살펴보면 매개변수가 전달될 때 인터페이스 유형으로 변환되었음을 알 수 있습니다.

// 以下为截取的源代码
func TypeOf(i interface{}) Type {
	eface := *(*emptyInterface)(unsafe.Pointer(&i))
	return toType(eface.typ)
}

func ValueOf(i interface{}) Value {
	if i == nil {
		return Value{}
	}
	escapes(i)

	return unpackEface(i)
}

위 내용은 Golang의 반영에 대한 자세한 설명(예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제