首頁 > 後端開發 > Golang > 無論接收器類型為何,如何在 Go 中動態呼叫介面{}上的方法?

無論接收器類型為何,如何在 Go 中動態呼叫介面{}上的方法?

Barbara Streisand
發布: 2024-12-02 01:39:09
原創
282 人瀏覽過

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

動態呼叫介面上的方法{},無論接收器類型為何

在 Go 的模板系統領域,反射起著至關重要的作用。當動態呼叫具有不同接收器類型的介面上的方法時,就會出現挑戰。 {}雖然這可以與已知類型無縫配合,但當資料包裝在介面{}中時,它會失敗。

問題陳述

考慮下列內容code:

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")
    }
}
登入後複製

觀察

  • 觀察
觀察

當資料是已知類型(main())時,動態方法呼叫成功。

當資料包裝在介面{}(Pass())時,它會失敗,第一次回傳「Pass()失敗」

問題

    問題在於當資料包裝在介面{}中時存取資料的位址。使用通常指向指標的 &i 在這種情況下不起作用。
    • 為了解決這個問題,我們需要處理所有可能的情況:
  1. interface{ }資料作為值,方法接收器作為value:

    如果資料是一個值,則建立一個指向它的指標。
  2. interface{} data as作為指標的值和方法接收器:

    如上所述,建立指向數據的指針。
  3. interface{}資料作為指針,方法接收器作為值:

    如果資料是指針,則檢索它指向的值to.
介面{}資料作為指針,方法接收者作為指標:

使用指標

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 ""
}
登入後複製

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
登入後複製
實作實作基於這個邏輯,我們🎜>我們可以建立一個通用函數來動態呼叫方法:透過此函數,我們現在可以動態呼叫方法,而不管接收器類型和介面如何{}包裝:

以上是無論接收器類型為何,如何在 Go 中動態呼叫介面{}上的方法?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板