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
252 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!

sumber:php.cn
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