本文共 809 字,预计阅读时间 3 分钟。
原生 C 交互(cgo)、严格类型限制(无泛型)、协程运行(Go routine)算是 Golang 的一些重要特性了。这些特性虽然有效,但是想要用好,却如同 黑魔法 一般,危险但威力巨大。作为初学者,面向 Google 和 StackOverflow 抄作业是快速而有效的选择。但是掌握一些黑魔法的原理也是十分有必要的,毕竟这是成为底层魔法师的必经之路。
本文从 cgo 说起,之后还有反射和协程两个部分。首先, import "C"
。如果之前没有使用过 cgo,可以先跑一下样例部分的代码,边读代码边看。
cgo 中 5 个重要的字符串相关函数
func C.CString(string) *C.char
该函数将 Go 字符串转为 C 字符串。转出的 C 字符串以 malloc 的方式在程序的 C 部分的堆上分配。需要注意的是:转出的 C 字符串不会受到 Go 的内存管理控制,也不会被 Go 的 GC 管辖,需要使用 C.free 释放。而 C.free 需要接收一个 unsafe.Pointer 类型的参数,所以通常用法为:
1 | x := C.CString("fuck world") |
func C.CBytes([]byte) unsafe.Pointer
该函数将 Go byte 数组转为 C 数组。转出的 C 字符串以 malloc 的方式在程序的 C 部分的堆上分配。需要注意的是:转出的 C 字符串不会受到 Go 的内存管理控制,也不会被 Go 的 GC 管辖,需要使用 C.free 释放。函数的转出的结果为 unsafe.Pointer,可以直接用 C.free 释放,也可以向 *C.char 等类型做强制转换。
func C.GoString(*C.char) string
该函数将 *C.char 类型转为 Go 字符串。通常可能以 C.GoString((*C.char)(unsafe.Pointer(&someCCharArray))) 形式出现。注意,如果这个 someCCharArray 是在 Go 中定义的(如 []byte 类型),需要将其通过 C.CBytes() 转为 unsafe.Pointer,而非直接对指针做强制类型转换。
func C.GoStringN(*C.char, C.int) string
该函数将 *C.char 类型前 N 位转为 Go 字符串。其中 C.int 不用做类型转换,可以直接使用 Go Int 类型。
func C.GoBytes(unsafe.Pointer, C.int) []byte
该函数将 *C.char 类型前 N 位转为 Go byte 数组。其中 C.int 不用做类型转换,可以直接使用 Go Int 类型。
样例
1 | package main |
依次输出为:
1 | [119 114 105 116 101 0 -1 -1 0 -10 0 106 23 -52 97 -64] // 正常 |