이 글에서는 당신에 대한 새로운 이해를 얻기 위해 GolangMedium Reflection에 대해 주로 이야기할 것입니다.
많은 사람들이 Go 언어를 일정 기간 사용해왔고, 심지어 1~2년 정도 사용한 사람도 있지만, 여전히 Go 언어에 대한 성찰에 대해 모호하고 자신감이 별로 없습니다. 그것을 사용할 때. [관련 권장사항: Go 비디오 튜토리얼, 프로그래밍 교육]
게다가 반사도 거의 사용하지 않습니다. 물론 직장에서 사용하는 것이 가장 간단하고 효율적입니다. 확장 가능하고 성능이 좋습니다. 일부 고급 사용법을 기계적으로 복사할 필요가 없습니다. 우리는 많은 것을 실험할 수 있습니다. 이번에는 성찰 놀이 방법에 대해 자세히 살펴보겠습니다
기사
- 다음 다섯 가지 측면에서 성찰이란 무엇입니까?
- 성찰의 규칙
- 사용 사례 및 유연한 적용
- Reflection 원리
- Summary
간단히 말하면, Reflection은
간단히 말해서, Reflection은 프로그램이 실행되는 동안 프로그램 자체에 액세스하고 수정하는 기능입니다. 예를 들어 프로그램이 실행 중일 때 프로그램의 필드 이름과 필드 값을 수정할 수 있으며, 프로그램 정보 등에 대한 인터페이스 액세스를 제공할 수도 있습니다.
이것은 Go 언어에서 제공되는 메커니즘입니다. . Go 언어 공용 라이브러리에서 Reflect의 사용에 대해 많이 볼 수 있습니다.
예를 들어 일반적으로 사용되는 fmt 패키지, commonly Used json 시퀀스 물론 앞서 언급한 gorm 라이브러리에서도 Reflection을 사용합니다. 그런데 왜 우리는 일반적으로 리플렉션을 사용합니까?
반사 능력을 바탕으로 당연히 우리가 제공하는 인터페이스는 들어오는 데이터 유형이 무엇인지 모르기 때문에 특정 데이터 유형은 프로그램이 실행될 때만 알 수 있습니다
그래서 사용하려면
어디에 반영되나요? 들어오는 데이터 유형이 무엇인지 확실하지 않기 때문에 이를 인터페이스로 설계했습니다{}. 인터페이스의 특성과 사용법에 대해 잘 모르는 경우 다음 기사를 확인하세요.
인터페이스{}에 관해 어떤 점에 주의해야 합니까?
인터페이스{}에 관해 어떤 점에 주의해야 합니까? 다음으로
- 먼저 세 가지 중요한 반성의 법칙에 주의하세요.
- 규칙에 따라 플레이하면 문제가 없을 것입니다 . 우리는 규칙을 모릅니다. 항상 절이 트리거되면 이상한 문제가 발생합니다
Reflection은 인터페이스 유형 변수를 반사 유형 객체로 변환할 수 있습니다
Reflection은 반사 유형 객체를 인터페이스 유형 변수로 변환할 수 있습니다We 만약 당신이 런타임에 리플렉션 유형 개체를 수정하려면 이 개체에 해당하는 값을 쓸 수 있어야 합니다. 위의 세 가지 규칙도 비교적 이해하기 쉽습니다.
우리는 일반적으로 사용하는 데이터 유형을 패키지(예: 안전하지 않은 패키지 또는 반영 패키지)의 지정된 데이터 유형으로 변환한 다음 패키지의 규칙에 따라 데이터를 수정합니다- 조끼를 바꾸는 것과 동일하며 다음과 같은 작업을 수행할 수 있습니다. do it 다양한 조작 사용 사례에 주의하고 유연하게 사용하세요
- 일반적으로 먼저 기본 응용 프로그램을 이해한 다음 그 원리와 왜 이런 식으로 사용될 수 있는지 연구하고 천천히 이해하게 됩니다. 더 깊이
법칙 1의 경우 인터페이스 유형 변수를 반사 유형 객체로 변환합니다
실제로 여기에 언급된 인터페이스 유형 변수의 경우etc.
와 같은 모든 데이터 유형의 변수를 전달할 수 있습니다.Reflection 유형 객체는 여기서 제공되는 reflect.Type
和 reflect.Value
对象,可以通过 reflect 包中提供的 TypeOf 和 ValueOf 函数得到
其中 reflect.Type
实际上是一个 interface ,他里面包含了各种接口需要进行实现,它里面提供了关于类型相关的信息
其中如下图可以查看到 reflect.Type
的所有方法,其中
- 绿色的 是所有数据类型都是可以调用的
- 红色的是 函数类型数据可以调用的
- 黑色的是 Map,数组 Array,通道 Chan,指针 Ptr 或者 切片Slice 可以调用的
- 蓝色的是结构体调用的
- 黄色的是通道 channel 类型调用的
reflect.Value
实际上是一个 struct,根据这个 struct 还关联了一组方法,这里面存放了数据类型和具体的数据,通过查看其数据结构就可以看出
type Value struct { typ *rtype ptr unsafe.Pointer flag }
看到此处的 unsafe.Pointer 是不是很熟悉,底层自然就可以将 unsafe.Pointer
转换成 uintptr
,然后再修改其数据后,再转换回来,对于 Go 指针不太熟悉的可以查看这篇文章:
写一个简单的 demo 就可以简单的获取到变量的数据类型和值
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) }
对于定律二,将 反射类型的对象 转换成 接口类型的变量
我们可以通过将 reflect.Value
类型转换成我们具体的数据类型,因为 reflect.Value
中有对应的 typ *rtype
以及 ptr unsafe.Pointer
例如我们可以 通过 reflect.Value
对象的 interface() 方法来处理
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) var res string res = reflect.ValueOf(demoStr).Interface().(string) fmt.Println("res == ",res) }
对于定律三,修改反射类型的对象
首先我们看上书的 demo 代码,传入 TypeOf 和 ValueOf 的变量实际上也是一个拷贝,那么如果期望在反射类型的对象中修改其值,那么就需要拿到具体变量的地址然后再进行修改,前提是这个变量是可写的
举个例子你就能明白
func main() { var demoStr string = "now reflect" v := reflect.ValueOf(demoStr) fmt.Println("is canset ", v.CanSet()) //v.SetString("hello world") // 会panic }
可以先调用 reflect.Value
对象的 CanSet
查看是否可写,如果是可写的,我们再写,如果不可写就不要写了,否则会 panic
那么传入变量的地址就可以修改了??
传入地址的思路没有毛病,但是我们去设置值的方式有问题,因此也会出现上述的 panic 情况
此处仔细看能够明白,反射的对象 v 自然是不可修改的,我们应该找到 reflect.Value
里面具体具体的数据指针,那么才是可以修改的,可以使用 reflect.Value
TypeOf 및 를 통해 액세스할 수 있는 Reflect 패키지의 reflect.Type
및 Reflect.Value
객체로 이해될 수 있습니다. Reflect 패키지에서 ValueOf
여기서
reflect.Type
은 실제로 구현해야 하는 다양한 인터페이스가 포함된 인터페이스이며 볼 수 있는 유형
에 대한 정보를 제공합니다. 아래와 같이 reflect.Type
의 모든 메소드에
green
은 모든 데이터 타입을 호출할 수 있으며- red
- 함수 타입 데이터를 호출할 수 있습니다 검은색은 Map, array Array, 채널 Chan, 포인터 Ptr 또는 슬라이스라고 할 수 있는 슬라이스

Reflect.Value
는 실제로 구조체입니다. 이 구조체에 따르면 데이터 유형과 특정 데이터를 저장하는 메서드 집합도 연결되어 있습니다. 데이터 구조를 보면 알 수 있습니다🎜type RDemo struct { Name string Age int Money float32 Hobby map[string][]string } func main() { tmp := &RDemo{ Name: "xiaomiong", Age: 18, Money: 25.6, Hobby: map[string][]string{ "sport": {"basketball", "football"}, "food": {"beef"}, }, } v := reflect.ValueOf(tmp).Elem() // 拿到结构体对象 h := v.FieldByName("Hobby") // 拿到 Hobby 对象 h1 := h.MapKeys()[0] // 拿到 Hobby 的第 0 个key fmt.Println("key1 name == ",h1.Interface().(string)) sli := h.MapIndex(h1) // 拿到 Hobby 的第 0 个key对应的对象 str := sli.Index(1) // 拿到切片的第 1 个对象 fmt.Println(str.CanSet()) str.SetString("helloworld") fmt.Println("tmp == ",tmp) }🎜여기를 참조하세요. unsafe.Pointer에 익숙하십니까? 맨 아래 레이어는 자연스럽게
unsafe.Pointer
를 uintptr
로 변환한 다음 해당 데이터를 수정하고 다시 변환할 수 있습니다. not 너무 익숙하다면 다음 기사를 확인해 보세요: 🎜🎜🎜GO의 포인터? 🎜🎜🎜변수의 데이터 유형과 값을 쉽게 얻을 수 있는 간단한 데모를 작성하세요🎜// rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte str nameOff ptrToThis typeOff }🎜

🎜법칙 2의 경우 반사 유형 객체를 인터페이스 유형 변수로 변환🎜🎜 🎜우리는 reflect.Value
유형을 특정 데이터 유형에 입력하세요. reflect.Value
및 ptr unsafe에 해당 <code>typ *rtype
이 있기 때문입니다. 포인터🎜🎜예를 들어 reflect.Value
객체🎜🎜
🎜// emptyInterface is the header for an interface{} value.type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}复制代码
🎜
🎜법칙 3의 경우 반사 유형 객체를 수정하세요🎜🎜먼저 살펴보겠습니다 책의 데모 코드에서 🎜TypeOf🎜 및 🎜ValueOf🎜에 전달된 변수는 실제로 복사본이므로 리플렉션 유형 개체에서 해당 값을 수정하려면 특정 변수의 주소를 가져온 다음 수정해야 합니다. 🎜이 변수는 쓰기 가능하다는 전제가 있습니다🎜🎜🎜예제를 보면 알 수 있습니다🎜rrreee🎜
🎜🎜먼저 reflect.Value
객체의 CanSet
를 호출하여 쓰기 가능한지 확인할 수 있습니다. 즉, 다시 쓰자. 쓸 수 없으면 쓰지 마세요. 그렇지 않으면 패닉 상태가 됩니다🎜🎜
🎜🎜그럼 전달된 변수의 주소를 수정할 수 있다는 건가요? ? 🎜🎜
🎜🎜들어오는 주소가 있습니다 아이디어에는 문제가 없지만 값을 설정하는 방식에 문제가 있으므로 위에서 언급한 패닉 상황도 발생하게 됩니다. 여기서 잘 살펴보면 반영된 객체 v가 당연히 수정 불가능하다는 것을 알 수 있습니다. reflect.Value
의 특정 데이터 포인터는 약간 더 복잡한 경우 reflect.Value
의 🎜Elem🎜 메서드를 사용할 수 있습니다. , 이렇게 단순한 경우라고 생각하실 수도 있고, 시연만 하면 괜찮겠지만, 직장에서 사용하면 바로 크래쉬가 납니다. 당연히 아직 완전히 이해되지는 않았습니다. 잘 소화되지 않았습니다. 작업에 대한 또 다른 예가 있습니다🎜🎜🎜구조에는 맵이 있고 맵의 키는 문자열이며 값은 []string🎜🎜🎜🎜입니다. 요구 사항은 🎜1🎜번째에 액세스하는 것입니다. 맵 키 🎜sport🎜를 사용하여 구조에서 취미 분야에 해당하는 슬라이스 요소를 추가하고 🎜 hellolworld🎜🎜🎜rrreee🎜🎜🎜로 수정합니다.

reflect.Value
객체의 CanSet
를 호출하여 쓰기 가능한지 확인할 수 있습니다. 즉, 다시 쓰자. 쓸 수 없으면 쓰지 마세요. 그렇지 않으면 패닉 상태가 됩니다🎜🎜

reflect.Value
의 특정 데이터 포인터는 약간 더 복잡한 경우 reflect.Value
의 🎜Elem🎜 메서드를 사용할 수 있습니다. , 이렇게 단순한 경우라고 생각하실 수도 있고, 시연만 하면 괜찮겠지만, 직장에서 사용하면 바로 크래쉬가 납니다. 당연히 아직 완전히 이해되지는 않았습니다. 잘 소화되지 않았습니다. 작업에 대한 또 다른 예가 있습니다🎜🎜🎜구조에는 맵이 있고 맵의 키는 문자열이며 값은 []string🎜🎜🎜🎜입니다. 요구 사항은 🎜1🎜번째에 액세스하는 것입니다. 맵 키 🎜sport🎜를 사용하여 구조에서 취미 분야에 해당하는 슬라이스 요소를 추가하고 🎜 hellolworld🎜🎜🎜rrreee🎜🎜🎜로 수정합니다.可以看到上述案例运行之后有时可以运行成功,有时会出现 panic 的情况,相信细心的 xdm 就可以看出来,是因为 map 中的 key 是 无序的导致的,此处也提醒一波,使用 map 的时候要注意这一点
看上述代码,是不是就能够明白咱们使用反射去找到对应的数据类型,然后按照数据类型进行处理数据的过程了呢
有需要的话,可以慢慢的去熟练反射包中涉及的函数,重点是要了解其三个规则,对象转换方式,访问方式,以及数据修改方式
反射原理
那么通过上述案例,可以知道关于反射中数据类型和数据指针对应的值是相当重要的,不同的数据类型能够用哪些函数这个需要注意,否则用错直接就会 panic
TypeOf
来看 TypeOf 的接口中涉及的数据结构
在 reflect 包中 rtype
是非常重要的,Go 中所有的类型都会包含这个结构,所以咱们反射可以应用起来,结构如下
// rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte str nameOff ptrToThis typeOff }
其中可以看到此处的 rtype
的结构保持和 runtime/type.go
一致 ,都是关于数据类型的表示,以及对应的指针,关于这一块的说明和演示可以查看文末的 interface{} 处的内容
ValueOf
从 ValueOf 的源码中,我们可以看到,重要的是 emptyInterface 结构
// emptyInterface is the header for an interface{} value.type emptyInterface struct { typ *rtype word unsafe.Pointer }复制代码
emptyInterface 结构中有 rtype
类型的指针, word 自然是对应的数据的地址了
reflect.Value
对象中的方法也是非常的多,用起来和上述说到的 reflect.Type
接口中的功能类似
关于源码中涉及到的方法,就不再过多的赘述了,更多的还是需要自己多多实践才能体会的更好
殊不知,此处的 reflect.Value
也是可以转换成 reflect.Type
,可以查看源码中 reflect\value.go
的 func (v Value) Type() Type {
其中 reflect.Value
,reflect.Type
,和任意数据类型
可以相互这样来转换
如下图:
总结
至此,关于反射就聊到这里,一些关于源码的细节并没有详细说,更多的站在一个使用者的角度去看反射需要注意的点
关于反射,大多的人是建议少用,因为是会影响到性能,不过如果不太关注这一点,那么用起来还是非常方便的
高级功能自然也是双刃剑,你用不好就会 panic,如果你期望去使用他,那么就去更多的深入了解和一步一步的吃透他吧
大道至简,反射三定律,活学活用
更多编程相关知识,请访问:编程视频!!
위 내용은 Golang의 리플렉션을 자세히 설명하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

解决Java反射异常(ReflectiveOperationException)的方法在Java开发中,反射(Reflection)是一种强大的机制,它允许程序在运行时动态地获取和操作类、对象、方法和属性等。通过反射,我们可以实现一些灵活的功能,比如动态创建对象、调用私有方法、获取类的注解等。然而,使用反射也会带来一些潜在的风险和问题,其中之一就是反射异常(

Golang函数的反射和类型断言的应用和底层实现在Golang编程中,函数的反射和类型断言是两个非常重要的概念。函数的反射可以让我们在运行时动态的调用函数,而类型断言则可以帮助我们在处理接口类型时进行类型转换操作。本文将深入讨论这两个概念的应用以及他们的底层实现原理。一、函数的反射函数的反射是指在程序运行时获取函数的具体信息,比如函数名、参数个数、参数类型等

如何在Java中使用反射调用方法反射是Java语言的一个重要特性,它可以在运行时动态地获取类的信息并操作类的成员,包括字段、方法和构造函数等。使用反射可以在编译时不知道具体类的情况下操作类的成员,这使得我们能够编写更加灵活和通用的代码。本文将介绍如何在Java中使用反射调用方法,并给出具体的代码示例。一、获取类的Class对象在Java中,要使用反射来调用方

Go语言作为一门静态类型语言,在代码编写时需要明确每个变量的类型。但是,在某些情况下,我们需要对程序中的类型进行动态的分析和操作,这时就需要用到反射机制。反射机制可以在程序运行时动态地获取程序对象的类型信息,并能够对其进行分析和操作,非常有用。但是,Go语言中反射机制也存在一些局限性,下面我们来详细了解一下。反射机制对性能的影响使用反射机制可以大大增强代

Python是一种灵活的编程语言,为开发人员提供了广泛的功能和工具。其强大的功能包括元编程——一种先进的技术,使开发人员能够在运行时动态地操作和生成代码。在本文中,我们将踏上高级Python元编程领域的旅程,特别关注动态代码生成和反射。通过采用这些技术,开发人员可以创建能够适应、修改甚至自省的代码,从而为创建灵活高效的应用程序开启了新的可能性世界。通过探索Python中动态代码生成和反射的概念和实际应用,我们将揭示元编程如何彻底改变开发过程,使开发人员能够生成健壮且高度适应性的代码。了解元编程元

Java是一种面向对象的编程语言,代码在编译后不直接变成机器语言,而是转化为字节码。字节码是Java虚拟机(JVM)可以理解的一种二进制形式。因此,在JVM上运行的程序可以在任何平台上运行,这就是Java的跨平台性。Java字节码的特征Java字节码是一种中间代码。编译器将Java源代码转换为字节码并存储在.class文件中。字节码指令可以轻松地转换为指示任

反射通常被定义为程序在执行时检查自身并修改其逻辑的能力。用不太专业的术语来说,反射是要求一个对象告诉您它的属性和方法,并更改这些成员(甚至是私有成员)。在本课程中,我们将深入探讨如何实现这一点,以及它何时可能有用。一点历史在编程时代的初期,出现了汇编语言。用汇编语言编写的程序驻留在计算机内部的物理寄存器中。通过读取寄存器可以随时检查其组成、方法和值。更重要的是,您可以在程序运行时通过简单地修改这些寄存器来更改程序。它需要对正在运行的程序有一些深入的了解,但它本质上是反思性的。与任何很酷的玩具一样

掌握Go语言的反射和元编程技术简介:随着计算机科技的不断发展,我们对于编程语言的要求也越来越高。Go语言作为一门现代化的编程语言,其简洁性、高效性和可靠性都受到广大开发者的认可。Go语言不仅提供了丰富的标准库,还支持强大的反射(reflection)和元编程(metaprogramming)技术,使得我们能够在运行时动态地获取和操作程序的结构信息。掌握Go语


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

SublimeText3 영어 버전
권장 사항: Win 버전, 코드 프롬프트 지원!

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경
