pkujhd / goloader

load and run golang code at runtime.
Apache License 2.0
507 stars 59 forks source link

如果我想要调用的函数参数个数和类型不定,应该如何使用? #50

Closed honey-yogurt closed 2 years ago

honey-yogurt commented 2 years ago

image

image

如果这个Hello函数参数个数以及类型不定,应该如何使用goloader?

pkujhd commented 2 years ago

不行,必须知晓函数签名

eh-steve commented 2 years ago

The JIT compiler in #66 will return the function symbols as a map[string]interface{} which you can either type switch/type assert on or use reflection to find out the number and types of function in/out args.

You can simply do:


loadable, err = jit.BuildGoFiles(jit.BuildConfig{}, "./path/to/file1.go", "/path/to/file2.go")
// or
loadable, err = jit.BuildGoPackage(jit.BuildConfig{}, "./path/to/package")
// or
loadable, err = jit.BuildGoText(jit.BuildConfig{}, `
package mypackage

import "encoding/json"

func MyFunc(input []byte) (interface{}, error) {
    var output interface{}
    err := json.Unmarshal(input, &output)
    return output, err
}

`)

if err != nil {
    panic(err)
}

module, symbols, err = loadable.Load()

if err != nil {
    panic(err)
}

MyFunc := symbols["MyFunc"].(func([]byte) (interface{}, error))
pkujhd commented 2 years ago

@eh-steve “.(func([]byte) (interface{}, error)” means you already know function type.

eh-steve commented 2 years ago

(Or you can type switch across multiple different function types, or use reflect to check the in/out args and then call it programmatically):


switch MyFunc := symbols["MyFunc"].(type) {
case func([]byte) (interface{}, error):
    out, err := MyFunc([]byte(`{"a": "b"}`))
case func(in1 []byte, in2 int) (map[string]interface{}, error):
    out, err := MyFunc([]byte(`{"a": "b"}`), 5)
}

or:

v := reflect.ValueOf(symbols["MyFunc"])
t := v.Type()

inputs := t.NumIn()
outputs := t.NumOut()
argv := make([]reflect.Value, inputs)
for i := 0; i < inputs; i++ {
    in := t.In(i)
    // check the type of `in` and decide where to get the value from/do any type conversion as required
    argv[i] = reflect.ValueOf(someInput)
}
results := v.Call(argv)