Go语言 利用interface{}传递函数指针 实现函数的强制类型转换

背景介绍

Golang的函数名不能使用&取指针,因而无法直接使用unsafe.Pointer,从而无法对函数做强制类型转换,或使用任意签名的函数作为参数。

问题分析

但是我们知道,fmt.Print系列的函数是可以以任意函数作为入参,打印其指针的。因此我们从分析其源码作为突破口的话,或许就可以找到解决之道了。
在分析源码之后,我们发现,因为Golang的任意类型变量都可以认为是实现了interface{}接口,因此通过将函数名转为接口,我们就可以得到一个能够取地址的变量。
这个变量不可能仅仅是一个函数指针,因为reflect包可以通过这个变量得到其类型,即传入的函数类型。因此,该变量适用如下结构体:

// 没有方法的interface
type eface struct {
    
    
	_type uintptr
	data  unsafe.Pointer
}

这里的data字段即是我们想要的函数指针了。拿到这个unsafe.Pointer之后,就可以通过强制类型转换将其复制给一个函数变量。这个函数变量的类型不一定要与传入的类型相同,因而可以实现函数的强制类型转换。

示例代码

这里使用了plugin包生成一个plugin.so,主函数加载该插件并将自己的Called函数指针传递给该插件,插件将函数指针保存在自己的函数变量mainfun,然后主函数调用插件的Call方法,由该方法调用函数指针mainfun,实现插件调用主函数中的函数。

主函数main.go

package main

import (
	"fmt"
	"plugin"
)

func Called() {
    
    
	fmt.Println("main func is called!")
}

func main() {
    
    
	h, err := plugin.Open("plugin/plugin.so")
	var initfun, callfun plugin.Symbol
	if err == nil {
    
    
		initfun, err = h.Lookup("Inita")
		if err == nil {
    
    
			callfun, err = h.Lookup("Call")
			if err == nil {
    
    
				fmt.Println("addr from main:", Called)
				initfun.(func(interface{
    
    }))(Called)
				Called()
				callfun.(func())()
			}
		}
	}
	if err != nil {
    
    
		fmt.Println(err)
	}
}

插件 plugin/plugin.go

package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

var mainfun func()

// 没有方法的interface
type eface struct {
    
    
	_type uintptr
	data  unsafe.Pointer
}

func Inita(ptr interface{
    
    }) {
    
    
	fmt.Println("addr val of ptr:", ptr)
	fmt.Printf("addr val of unsafe: 0x%x\n", reflect.ValueOf(ptr).Pointer())
	f := (*eface)(unsafe.Pointer(&ptr)).data
	mainfun = *(*(func()))(unsafe.Pointer(&f))
	fmt.Println("addr from plug:", mainfun)
}

func Call() {
    
    
	mainfun()
}

编译运行如下:

go build -ldflags "-s -w" -o main
cd plugin
go build -buildmode=plugin -ldflags "-s -w"
cd ..
./main 

输出结果如下

addr from main: 0x40cdc40
addr val of ptr: 0x40cdc40
addr val of unsafe: 0x40cdc40
addr from plug: 0x40cdc40
main func is called!
main func is called!

猜你喜欢

转载自blog.csdn.net/u011570312/article/details/120774188