分享
  1. 首页
  2. 文章

Golang 隐藏技能 -- 访问私有成员

郭老汉 · · 3761 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

警告一下!以下代码均不是常规操作,且存在各种潜在不可控的风险。在项目中应用有可能被同事打死,慎用!!!

1.调用其他包中公有结构的私有成员变量

如果需要引用某个包中公有结构体的私有变量,而这个变量又没有提供对应的访问方法。那么如何绕过"小写不公开"这个限制呢?简单介绍一种方法直接通过变量地址访问变量:

package other1
import "fmt"
type TestPointer struct {
 A int
 b int // 私有变量
}
func (T *TestPointer) OouPut() {
 fmt.Println("TestPointer OouPut:", T.A, T.b)
}
package main
import (
 "fmt"
 "test/test4/other1"
 "unsafe"
)
func main() {
 T := other1.TestPointer{A:1}
 pb := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&T)) + 8))
 /*
 Tmp := uintptr(unsafe.Pointer(&T)) + 8)
 pb := (*int)(unsafe.Pointer(Tmp)
 千万不能出现这种用临时变量中转一下的情况。因为GC可能因为优化内存碎片的原因移动了这个对象。只保留了指针的地址是没有意义的。
 */
 *pb = 2
 T.OouPut() //1 2
}

用unsafe包中的unsafe.Pointer获取到结构体对象的首地址,然后加上想访问的私有变量的偏移地址就是私有变量的地址。关于成员变量偏移量的问题请参阅 内存对齐

2.调用其他包的私有func

go提供了一个编译指令,绕过编译器检查。直接访问func的实现
//go:linkname

package other1
import "fmt"
func privateFunc() {
 fmt.Println("this is private func")
}
package main
import (
 _ "test/test4/other1"
 _ "unsafe"
)
// call private func
//go:linkname private_func test/test4/other1.privateFunc
func private_func()
func main() {
 private_func() // this is private func
}

关于编译指令可以参阅 编译指令Command compile
上面代码需要在调用者(这里是main.go)同目录添加一个.s汇编文件,骗过编译器。让编译器认为是实现是在.s汇编文件中,从而跳过检查

3. 调用其他包的公有结构的私有方法

package other1
import "fmt"
type PublicStruct struct {
 I int
 b int
}
func (p *PublicStruct) f(a int) {
 println("PublicStruct f()", p.I, p.b, a)
}
package main
import (
 "test/test4/other1"
 _ "unsafe"
)
// 调用其他包的公有结构的私有func
//go:linkname public_struc_private_func test/test4/other1.(*PublicStruct).f
func public_struc_private_func(p *other1.PublicStruct, a int)
func main() {
 // 先构造一个other1.PublicStruct
 p := &other1.PublicStruct{I:1}
 public_struc_private_func(p, 100) // PublicStruct f() 1 0 100
}

和上面的类似用linkname指令骗过编译器。这里声明了一个指针接收者的func public_struc_private_func
第一个参数是对应对象的指针,第二个参数开始是对应func需要的参数。
其实这就是指针接收者func原本的实现方式(即 本质上是一个普通的函数,只是隐式传递了对象的指针)

4. 调用其他包的私有全局变量

package other1
var private_m = map[int]string {
 1:"a",
}
import (
 "fmt"
 _ "test/test4/other1"
 _ "unsafe"
) // 调用其他包的私有全局变量
//go:linkname private_member test/test4/other1.private_m
var private_member map[int]string
func main() {
 fmt.Println(private_member[1]) // a
 private_member[2] = "b"
 for k, v := range private_member {
 fmt.Println(k, v) // 1 a; 2 b
 }
}

和上面的linkname类似,骗过编译器。直接访问变量


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:郭老汉

查看原文:Golang 隐藏技能 -- 访问私有成员

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
3761 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏