golang使用linkname(非反射)调用非导出方法

package a

func test() {
    println("this is a/test()")
}

type A struct {
    Name string
}

func (*A) test1() {
    println("this is a/(*A).test1()")
}

func (A) test2() {
    println("this is a/A.test2()")
}

func (a *A) setName(name string) {
    a.Name = name
}

func (a *A) getName() string {
    return a.Name
}
package b

import (
    "gitlab.meitu.com/mtgo/fw/fortest/a"
    _ "unsafe" // linkname require unsafe
)

//go:linkname Test gitlab.meitu.com/mtgo/fw/fortest/a.test
func Test()

// 指针接收器
//go:linkname Test1 gitlab.meitu.com/mtgo/fw/fortest/a.(*A).test1
func Test1(_ *a.A)

// 非指针接收器
//go:linkname Test2 gitlab.meitu.com/mtgo/fw/fortest/a.A.test2
func Test2(_ a.A)

//go:linkname GetName gitlab.meitu.com/mtgo/fw/fortest/a.(*A).getName
func GetName(_ *a.A) string

//go:linkname SetName gitlab.meitu.com/mtgo/fw/fortest/a.(*A).setName
func SetName(_ *a.A, name string)
package main

import (
    "fmt"
    "gitlab.meitu.com/mtgo/fw/fortest/a"
    "gitlab.meitu.com/mtgo/fw/fortest/b"
)

func main() {
    b.Test()
    var v a.A
    b.Test1(&v)
    b.Test2(v)
    b.SetName(&v, "robin")
    fmt.Println(b.GetName(&v))

}

/*
output:
this is a/test()
this is a/(*A).test1()
this is a/A.test2()
robin
*/

需要注意的是,在b包的目录下需要放个.s后缀的文件,原因在于Go在编译的时候会启用-complete编译器flag,它要求所有的函数必需包含函数体。创建一个空的汇编语言文件绕过这个限制。

 


附:有局限的小玩意,见 https://github.com/alangpierce/go-forceexport

 

发表评论

邮箱地址不会被公开。 必填项已用*标注