代码之家  ›  专栏  ›  技术社区  ›  Niklas Rosencrantz

如何将name函数放宽为变量

  •  1
  • Niklas Rosencrantz  · 技术社区  · 6 年前

    我在Go中编写了一个插件生成器。这个 repo is open .

    该项目在一些临时文件中创建了一些go代码,定义了一个从命令行参数中获取的函数,将该代码编译成插件,加载该插件,获取其中的函数,并使用参数调用该函数,然后打印结果。

    我们希望能够处理几个函数和几个插件。例如,函数 SUM 身体的 return x+y; 一个函数 PROD 身体的 return x*y 等等。

    我不希望生成的代码总是使用 常量名称函数。生成的.go文件不能包含 其名称在运行时给定的函数,即 funame 在下面的代码中?围棋语言有什么禁止的特征吗?

    //TODO: Investigate how to relax the name FUNCTION into a variable
    type Xinterface interface {
        FUNCTION(x int, y int) int
    }
    

    完整代码

    package main
    
    import (
        "fmt"
        "os"
        "os/exec"
        "path/filepath"
        "plugin"
        "reflect"
        "strconv"
        "strings"
    )
    
    
    //TODO: Investigate how to relax the name FUNCTION into a variable
    type Xinterface interface {
        FUNCTION(x int, y int) int
    }
    
    func main() {
        //Declare good variable names and create the file for the code
        funame := os.Args[1]
        funamel := strings.ToLower(funame)
        funamet := strings.Title(funame)
        fubody := os.Args[2]
        x1, err := strconv.Atoi(os.Args[3])
        y1, err := strconv.Atoi(os.Args[4])
        filename := fmt.Sprintf("/tmp/%s.go", funame)
        f, err := os.Create(filename)
        if err != nil {
            fmt.Println(err)
            return
        }
        //Here comes the program
        strprg := fmt.Sprintf(`package main 
    import (
        "fmt"
    )
    type %s string 
    func(s %s) FUNCTION (x int, y int) int { fmt.Println("")
    %s} 
    var %s %s`, funamel, funamel, fubody, funamet, funamel)
        fmt.Printf("func(s %s) FUNCTION (x int, y int) int { \n", funamel)
        fmt.Printf("start of %s: x=%d, y=%d\n", funamel, x1, y1)
        l, err := f.WriteString(strprg)
        if err != nil {
            fmt.Println(err)
            f.Close()
            return
        }
        fmt.Println(l, "bytes written successfully")
        err = f.Close()
        if err != nil {
            fmt.Println(err)
            return
        }
    
        ex, err := os.Executable()
        if err != nil {
            panic(err)
        }
        exPath := filepath.Dir(ex)
        fmt.Println(exPath)
        fmt.Println("compiling plugin")
        cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", fmt.Sprintf("%s%s%s", "/tmp/", funame, ".so"), fmt.Sprintf("%s%s%s", "/tmp/", funame, ".go"))
    
        out, err2 := cmd.Output()
        fmt.Println(out)
    
        if err2 != nil {
            fmt.Println(err2)
            return
        }
        fmt.Println("loading module")
        // load module
        // 1. open the so file to load the symbols
        plug, err := plugin.Open(fmt.Sprintf("%s%s%s", "/tmp/", funame, ".so"))
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
        fmt.Println("looking up symbol")
        // 2. look up a symbol (an exported function or variable)
        // in this case, variable funame
        symX, err := plug.Lookup(funame)
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
        fmt.Println("checking module")
        // 3. Assert that loaded symbol is of a desired type
        // in this case interface type X (defined above)
        var myvar Xinterface
        myvar, ok := symX.(Xinterface)
        if !ok {
            fmt.Println(fmt.Sprintf("unexpected type from module symbol %s", reflect.TypeOf(symX.(Xinterface))))
            os.Exit(1)
        }
    
        // 4. use the module
    
        fmt.Println(myvar.FUNCTION(x1, y1))
        fmt.Println(fmt.Sprintf("Generated code: %s", fmt.Sprintf("/tmp/%s%s", funamet , ".go") ))
        fmt.Println(fmt.Sprintf("Generated object file: %s", fmt.Sprintf("/tmp/%s%s", funamet , ".so") ))
    
    }
    

    示例用法:

    $ go run forbasile.go SUM 'return x+y' 3 5
    func(s sum) FUNCTION (x int, y int) int { 
    start of sum: x=3, y=5
    131 bytes written successfully
    /tmp/go-build104174513/b001/exe
    compiling plugin
    []
    loading module
    looking up symbol
    checking module
    
    8
    Generated code: /tmp/SUM.go
    Generated object file: /tmp/SUM.so
    $ go run forbasile.go SUMSQUARE 'return x*x + y*y' 3 4
    func(s sumsquare) FUNCTION (x int, y int) int { 
    start of sumsquare: x=3, y=4
    161 bytes written successfully
    /tmp/go-build555823501/b001/exe
    compiling plugin
    []
    loading module
    looking up symbol
    checking module
    
    25
    Generated code: /tmp/SUMSQUARE.go
    Generated object file: /tmp/SUMSQUARE.so
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Billy Yuan    6 年前

    godoc

    符号是指向变量或函数的指针。

    例如,一个插件定义为

    package main
    
    import "fmt"
    
    func F() { fmt.Printf("Hello, number %d\n", V) }
    

    可以使用open函数加载,然后可以访问导出的包符号v和f

    p, err := plugin.Open("plugin_name.so")
    if err != nil {
        panic(err)
    }
    f, err := p.Lookup("F")
    if err != nil {
        panic(err)
    }
    f.(func())() // prints "Hello, number 7"
    

    “f”只是一个字符串,因此您无论如何都可以在运行时更改其值。