検索
ホームページバックエンド開発GolangGolangのリフレクションを詳しく解説した記事
Golangのリフレクションを詳しく解説した記事Dec 14, 2022 pm 08:26 PM
golang言語を移動反射

この記事では主に Golang でのリフレクションについて説明し、皆さんについて新たな理解を得ることができれば幸いです。

Golangのリフレクションを詳しく解説した記事

Go 言語を一定期間使用している人は多く、中には 1 ~ 2 年使用している人もいますが、反映についてはまだ曖昧です。 Go言語. 、私は自分の心にあまり自信がありません。 [関連する推奨事項: Go ビデオ チュートリアル プログラミング教育 ]

さらに、リフレクションはほとんど使用されません。もちろん、それ自体に問題はありません。当然のことながら、最もシンプルで、最も効率的で、スケーラブルで、パフォーマンスの良い方法で処理するのが最も良い方法です。高度な使用法を機械的にコピーする必要はありません。結局のところ、仕事は私たちの実験場ではありません。実際に行って実験することができます。自分で、 this リフレクションの遊び方を詳しく見てみましょう

この記事では次の 5 つの側面から説明します

  • リフレクションとは
    #リフレクションのルール
##ユースケースと柔軟なアプリケーション
  • ##リフレクションの原則
  • 概要
  • リフレクションとは何かを簡単に見てみる

簡単に言うと、リフレクションとは、次のことにアクセスする機能です。プログラムの実行中にプログラム自体を変更する

たとえば、プログラムの実行中に、プログラムのフィールド名とフィールド値を変更したり、プログラムにインターフェイスのアクセス情報を提供したりすることもできます。

これは Go 言語で提供されるメカニズムです。言語のパブリック ライブラリでの Reflect の使用については多くのことがわかります。

たとえば、一般的に使用される fmt パッケージでは、

一般的に使用される

json シリアル化と逆シリアル化、当然、先ほど述べた gorm ライブラリもリフレクションを使用します

しかし、なぜ一般的に「リフレクションはどうですか?」を使用するのでしょうか?

リフレクションの機能によると、当然のことですが、提供するインターフェイスでは受信データ型がわからないため、特定のデータ型はプログラムの実行中にのみわかります

しかし、コーディング時には、プログラムの実行時に渡された型が何であるかを検証し (json のシリアル化など)、この特定のデータを操作したいとも考えています。このとき、リフレクションの機能を使用する必要があります

リフレクションが使用されている場所では、

インターフェイス{}

が表示されるのは驚くことではありませんか?

受信データ型が何になるかわからないからこそ、インターフェースとして設計しました。{}。インターフェースの特徴や使い方がわからない場合は、過去の記事を確認してください。 . :

インターフェースについて注意すべき点は何ですか?{}
#インターフェースについて注意すべき点は何ですか?{}次
  • #まず反省のルールに注意してください

まず、反省の 3 つの重要な法則に注意してください。ルールを理解した後、私たちはルールに従います プレーする際には問題はありません

, ルールを知らずに常に条項を発動した場合にのみ、奇妙な問題が発生します

##反省することができますインターフェイスの変更に使用されます。 Type 変数はリフレクション タイプのオブジェクトに変換されます。

  • Reflection は、リフレクション タイプのオブジェクトをインターフェイス タイプの変数に変換できます。

    実行時に変更するリフレクション タイプのオブジェクト。次に、このオブジェクトに対応する値が書き込み可能である必要があります。
  • 上記の 3 つのルールも比較的理解しやすいものです。前に説明した安全でないパッケージ内のポインタをまだ覚えていますか?
  • 一般的に使用されるデータ型をパッケージ内の指定されたデータ型 (安全でないパッケージやリフレクト パッケージなど) に変換し、パッケージ内のルールに従ってデータを変更します

まったく同等そのため、ベストを変更することで、さまざまな操作を行うことができます。

ユースケースに注意して柔軟に使用してください

一般的には、最初に基本的なアプリケーションを学び、次に、その原則を学び、なぜこの方法で使用できるのかを学び、ゆっくりとより深く理解していきます。

法則 1 については、インターフェース型変数をリフレクション型オブジェクトに変換します

実際 ここで説明したインターフェイス タイプの変数については、int、float、string、map、slice、struct などの任意のデータ タイプの変数を渡すことができます。

リフレクション タイプ オブジェクトは、ここでは、reflect リフレクション パッケージの reflect.Type および reflect.Value オブジェクトとして理解できます。これらは、で提供される TypeOf# を通じて使用できます。 ## および ValueOf 関数は

を取得します (

reflect.Type は実際にはインターフェースであり、実装する必要があるさまざまなインターフェースが含まれています)。 Type 関連情報

以下に示すように、

reflect.Type のすべてのメソッドが表示されます。その中には、

  • green があります。はすべてのデータです。型はすべて呼び出し可能です。
  • 赤いものは、呼び出し可能な関数型のデータです。
    Black
  • は、Map、配列 Array、チャネル Chan、ポインタ Ptr、またはスライス Slice です。
    青色の
  • は、実行できる # です。
##Yellow
    はチャネル タイプの呼び出し

reflect.Value

実際 上記は構造体です。この構造体に従って、データ型と特定のデータを格納するメソッドのセットも関連付けられています。データ構造を見るとわかります

type Value struct {
   typ *rtype
   ptr unsafe.Pointer
   flag
}
参照unsafe.Pointer はこちら ご存知ですか? 最下位層は自然に unsafe.Pointer

uintptr に変換し、そのデータを変更してから元に戻すことができます。 、次の記事を確認できます:

#GO のポインタ?
  • 変数のデータ型と値を簡単に取得するための簡単なデモを作成します
  • func main() {   var demoStr string = "now reflect"
       fmt.Println("type:", reflect.TypeOf(demoStr))
       fmt.Println("value:", reflect.ValueOf(demoStr))
    }

法律の場合 2 番目、リフレクション型オブジェクトをインターフェイス型変数に変換します

reflect であるため、

reflect.Value

型を特定のデータ型に変換できます。対応する # があります。 ##typ *rtype および ptr unsafe.Pointer in Value . たとえば、reflect.Value オブジェクトのインターフェイスを渡すことができます。 () に対処するメソッド

#

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)
}

法則 3 については、リフレクション タイプのオブジェクトを変更します

最初に、デモ コードでは、

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

を呼び出して、書き込み可能かどうかを確認できます。書き込み可能であれば、再度書き込みます。書き込み可能でない場合は、書き込みを行わないでください。そうしないとパニックになります

では、渡された変数のアドレスは変更できるのでしょうか? ?

#アドレスを渡すという考えには何も問題はありませんが、値の設定方法に問題があるため、上記のパニック状況が発生します。

reflect.Value で特定のデータ ポインタを見つける必要があります。そうすれば、それを変更できます。

reflect.Value

Elem

メソッドもう少し複雑なもの

上記のケースを見てみればそう感じるかもしれません 簡単なケースはデモするまでは大丈夫ですが、仕事で使うとすぐにクラッシュしてしまいます 当然まだ完全には理解されていません。うまく消化されていません。これは仕事からの別の例です。

#A 構造体にはマップが含まれており、マップ内のキーは文字列で、値は []文字列## です。

#要件は、構造内の趣味フィールドに対応するマップ キーの ## 番目のスライス (

sport

##1
    要素) にアクセスし、それらを
  • に変更することです。 hellolworld
    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)
    }
  • 可以看到上述案例运行之后有时可以运行成功,有时会出现 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.gofunc (v Value) Type() Type {

    其中   reflect.Value  ,reflect.Type ,和任意数据类型 可以相互这样来转换

    如下图:

    总结

    至此,关于反射就聊到这里,一些关于源码的细节并没有详细说,更多的站在一个使用者的角度去看反射需要注意的点

    关于反射,大多的人是建议少用,因为是会影响到性能,不过如果不太关注这一点,那么用起来还是非常方便的

    高级功能自然也是双刃剑,你用不好就会 panic,如果你期望去使用他,那么就去更多的深入了解和一步一步的吃透他吧

    大道至简,反射三定律,活学活用

    更多编程相关知识,请访问:编程视频!!

以上がGolangのリフレクションを詳しく解説した記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は掘金社区で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
解决Java反射异常(ReflectiveOperationException)的方法解决Java反射异常(ReflectiveOperationException)的方法Aug 26, 2023 am 09:55 AM

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

Golang函数的反射和类型断言的应用和底层实现Golang函数的反射和类型断言的应用和底层实现May 16, 2023 pm 12:01 PM

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

如何在Java中使用反射调用方法如何在Java中使用反射调用方法Dec 23, 2023 am 08:18 AM

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

Go 语言中的反射机制的局限性是什么?Go 语言中的反射机制的局限性是什么?Jun 09, 2023 pm 11:31 PM

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

高级Python元编程:动态代码生成和反射高级Python元编程:动态代码生成和反射Sep 06, 2023 pm 09:13 PM

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

Java中的字节码与反射技术Java中的字节码与反射技术Jun 15, 2023 pm 10:47 PM

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

Java底层技术解读:如何实现反射与动态代理Java底层技术解读:如何实现反射与动态代理Nov 08, 2023 pm 05:12 PM

Java底层技术解读:如何实现反射与动态代理引言:Java是一种面向对象的编程语言,在开发过程中,我们经常需要使用到一些底层技术,比如反射和动态代理。本文将介绍反射和动态代理的原理,并给出具体的代码示例,帮助读者更好地理解和运用这两个底层技术。一、反射(Reflection)的原理反射是Java中一种强大而灵活的特性,它使得我们可以在运行时动态地获取和操作一

掌握Go语言的反射和元编程技术掌握Go语言的反射和元编程技术Nov 30, 2023 am 10:18 AM

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

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境