ホームページ > バックエンド開発 > Golang > レシーバーのタイプに関係なく、Go の「interface{}」でメソッドを動的に呼び出すにはどうすればよいですか?

レシーバーのタイプに関係なく、Go の「interface{}」でメソッドを動的に呼び出すにはどうすればよいですか?

DDD
リリース: 2024-12-26 20:04:22
オリジナル
604 人が閲覧しました

How to Dynamically Invoke Methods on `interface{}` in Go, Regardless of Receiver Type?

レシーバーのタイプに関係なく、インターフェースでのメソッドの動的呼び出し{}

この記事では、インターフェースでメソッドを動的に呼び出そうとするときに直面する問題について説明します。{}囲碁で。私たちの目標は、この課題を克服し、基になるデータ型やレシーバーの型に関係なく効率的なメソッド呼び出しを可能にすることです。

問題

Go でインターフェイス{}を扱うとき、次の制限に遭遇しました。動的メソッド呼び出し: インターフェース内に保存されているデータがポインタの場合、そのアドレスにアクセスする際に問題が発生しました。{}その結果、ポインター レシーバーを持つメソッドを動的に呼び出すことができませんでした。

解決策

この問題を解決するには、次の 4 つのケースを含む手法を活用します。

  1. Interface{} データは値、受信者は値です: この場合、変更は行われません。
  2. インターフェース{} データはポインタ、レシーバは値です。 インターフェース{} データへの新しいポインタを作成し、参照される値を取得します。
  3. インターフェース{} データは値、レシーバーはポインタです。 インターフェースへの新しいポインタを作成します。{} data.
  4. インターフェース{} データはポインタ、レシーバはポインタです: 既存のポインタを利用します。

適切なデータ型を決定した後、値とポインターの両方でメソッドの存在について追加のチェックを実行します。そうすることで、メソッドが値レシーバーとして宣言されているか、ポインター レシーバーとして宣言されているかに関係なく、確実にメソッドを呼び出すことができます。

概念実証

次のコードは、ソリューションの実装を示しています。

package main

import (
    "fmt"
    "reflect"
)

type Test struct {
    Start string
}

// value receiver
func (t Test) Finish() string {
    return t.Start + "finish"
}

// pointer receiver
func (t *Test) Another() string {
    return t.Start + "another"
}

func CallMethod(i interface{}, methodName string) interface{} {
    var ptr reflect.Value
    var value reflect.Value
    var finalMethod reflect.Value

    value = reflect.ValueOf(i)

    // if we start with a pointer, we need to get value pointed to
    // if we start with a value, we need to get a pointer to that value
    if value.Type().Kind() == reflect.Ptr {
        ptr = value
        value = ptr.Elem()
    } else {
        ptr = reflect.New(reflect.TypeOf(i))
        temp := ptr.Elem()
        temp.Set(value)
    }

    // check for method on value
    method := value.MethodByName(methodName)
    if method.IsValid() {
        finalMethod = method
    }
    // check for method on pointer
    method = ptr.MethodByName(methodName)
    if method.IsValid() {
        finalMethod = method
    }

    if (finalMethod.IsValid()) {
        return finalMethod.Call([]reflect.Value{})[0].Interface()
    }

    // return or panic, method not found of either type
    return ""
}

func main() {
    i := Test{Start: "start"}
    j := Test{Start: "start2"}

    fmt.Println(CallMethod(i, "Finish"))
    fmt.Println(CallMethod(&i, "Finish"))
    fmt.Println(CallMethod(i, "Another"))
    fmt.Println(CallMethod(&i, "Another"))
    fmt.Println(CallMethod(j, "Finish"))
    fmt.Println(CallMethod(&j, "Finish"))
    fmt.Println(CallMethod(j, "Another"))
    fmt.Println(CallMethod(&j, "Another"))
}
ログイン後にコピー

この手法を採用すると、受信機のタイプに関係なくインターフェースでメソッドを動的に呼び出すことができ、堅牢で適応性のあるコードが容易になります。{}行きましょう

以上がレシーバーのタイプに関係なく、Go の「interface{}」でメソッドを動的に呼び出すにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート