在使用 Golang 的某些情况下(当然,应该是在万不得已的情况下),你可能需要调用引入的某个包中的某些私有全局变量或函数(包括方法)。事实上,Golang 是有一些未在官方文档中公布的相关隐藏技能的,这些技能在 Golang 开源的标准库代码中出现,终究被挖了出来。

调用私有函数

somewhere.com/someone/another
package another

func inc(i int) int {
    return i + 1
}
inc
package main

import (
    _ "unsafe"

    _ "somewhere.com/someone/another"
)

//go:linkname inc somewhere.com/someone/another.inc
func inc(i int) int

func main() {
    println(inc(2))
}
//export//go:linkname
//go:linkname
unsafe*.s

调用公开结构的私有方法

Clsm
package another

type Cls struct {
    I int
}

func (c *Cls) m() {
    println(c.I)
}
package main

import (
    _ "unsafe"

    "somewhere.com/someone/another"
)

//go:linkname m somewhere.com/someone/another.(*Cls).m
func m(c *another.Cls)

func main() {
    c := &another.Cls{2}
    m(c)
}
(*S)

调用私有结构的私有方法

结构的定义不像函数那样是在符号表进行链接,所以私有结构的定义需要在本包重复进行一次。也因为本包已有此结构,所以可直接在结构上声明方法,无须显式表达 this 指针。

package another

type cls struct {
    I int
}

func (c *cls) m() {
    println(c.I)
}
package main

import (
    _ "unsafe"

    _ "somewhere.com/someone/another"
)

type cls struct {
    I int
}

//go:linkname (*cls).m somewhere.com/someone/another.(*cls).m
func (c *cls) m()

func main() {
    c := &cls{2}
    c.m()
}

到这里,对于私有结构的公开方法的调用,相信你已心里有数了吧。:D

调用私有全局变量

和函数一样,全局变量也存在于符号表中,因此也可以有这种操作。

package another

var m = map[int]string{
    1: "a",
}

func M(i int) string {
    return m[i]
}
package main

import (
    _ "unsafe"

    "somewhere.com/someone/another"
)

//go:linkname m somewhere.com/someone/another.m
var m map[int]string

func main() {
    println(m[1])
    m[2] = "b"
    println(another.M(2))
}

References