Rumah > pembangunan bahagian belakang > Golang > Bagaimana untuk Memanggil Kaedah Secara Dinamik pada antara muka{} dalam Go, Tanpa mengira Jenis Penerima?

Bagaimana untuk Memanggil Kaedah Secara Dinamik pada antara muka{} dalam Go, Tanpa mengira Jenis Penerima?

Barbara Streisand
Lepaskan: 2024-12-02 01:39:09
asal
329 orang telah melayarinya

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

Kaedah Memanggil Secara Dinamik pada Antara Muka{} Tanpa mengira Jenis Penerima

Dalam bidang sistem templat dalam Go, refleksi memainkan peranan yang penting. Cabaran timbul apabila memanggil kaedah secara dinamik pada antara muka{} dengan pelbagai jenis penerima. Walaupun ini berfungsi dengan lancar dengan jenis yang diketahui, ia gagal apabila data dibalut dalam antara muka{}.

Pernyataan Masalah

Pertimbangkan kod berikut:

type Test struct {
    Start string
}

func (t *Test) Finish() string {
    return t.Start + "finish"
}

func Pass(i interface{}) {
    _, ok := reflect.TypeOf(&i).MethodByName("Finish")
    if ok {
        fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0])
    } else {
        fmt.Println("Pass() fail")
    }
}

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

    Pass(i)
    _, ok := reflect.TypeOf(&i).MethodByName("Finish")
    if ok {
        fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0])
    } else {
        fmt.Println("main() fail")
    }
}
Salin selepas log masuk

Pemerhatian

  • Apabila data ialah jenis yang diketahui (main()), panggilan kaedah dinamik berjaya.
  • Apabila data dibalut dalam antara muka{} (Pass()), ia gagal, mengembalikan "Pass() fail" pada panggilan pertama.

Masalahnya

Masalahnya terletak pada mengakses alamat data apabila ia dibungkus dalam antara muka{}. Menggunakan &i, yang biasanya menghala ke penunjuk, tidak berfungsi dalam senario ini.

Penyelesaian

Untuk menangani perkara ini, kita perlu mengendalikan semua senario yang mungkin:

  1. antara muka{} data sebagai nilai dan penerima kaedah sebagai nilai:

    • Jika data ialah nilai, buat penunjuk kepadanya.
  2. antara muka{} data sebagai penerima nilai dan kaedah sebagai penunjuk:

    • Seperti di atas, buat penunjuk ke data.
  3. antara muka{} data sebagai penunjuk dan penerima kaedah sebagai nilai:

    • Jika data itu penunjuk, dapatkan semula nilai yang ditunjukkannya kepada.
  4. antara muka{} data sebagai penunjuk dan penerima kaedah sebagai penunjuk:

    • Gunakan penunjuk secara langsung.

Pelaksanaan

Berdasarkan logik ini, kita boleh mencipta fungsi umum untuk memanggil kaedah secara dinamik:

func CallMethod(i interface{}, methodName string) interface{} {
    // Handle all scenarios
    var ptr, value, finalMethod reflect.Value
    value = reflect.ValueOf(i)
    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 and pointer
    method := value.MethodByName(methodName)
    if method.IsValid() {
        finalMethod = method
    }
    method = ptr.MethodByName(methodName)
    if method.IsValid() {
        finalMethod = method
    }

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

    // Method not found
    return ""
}
Salin selepas log masuk

Dengan fungsi ini, kita kini boleh memanggil kaedah secara dinamik tanpa mengira jenis penerima dan antara muka{} pembalut:

i := Test{Start: "start"}
j := Test{Start: "start2"}

fmt.Println(CallMethod(i, "Finish"))
// Output: startfinish
fmt.Println(CallMethod(&i, "Finish"))
// Output: startfinish
fmt.Println(CallMethod(i, "Another"))
// Output:
fmt.Println(CallMethod(&i, "Another"))
// Output: start2another
fmt.Println(CallMethod(j, "Finish"))
// Output: startfinish
fmt.Println(CallMethod(&j, "Finish"))
// Output: start2finish
fmt.Println(CallMethod(j, "Another"))
// Output:
fmt.Println(CallMethod(&j, "Another"))
// Output: start2another
Salin selepas log masuk

Atas ialah kandungan terperinci Bagaimana untuk Memanggil Kaedah Secara Dinamik pada antara muka{} dalam Go, Tanpa mengira Jenis Penerima?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan