码农桃花源
GitHub
知乎
掘金
博客园
Search…
码农桃花源
README
channel
map
interface
标准库
context
unsafe
如何利用unsafe包修改私有成员
Go指针和unsafe.Pointer有什么区别
如何实现字符串和byte切片的零拷贝转换
如何利用unsafe获取slice&map的长度
goroutine 调度器
编译和链接
反射
数组和切片
GC
Powered By
GitBook
如何利用unsafe获取slice&map的长度
获取 slice 长度
通过前面关于 slice 的
文章
,我们知道了 slice header 的结构体定义:
1
// runtime/slice.go
2
type
slice
struct
{
3
array unsafe
.
Pointer
// 元素指针
4
len
int
// 长度
5
cap
int
// 容量
6
}
Copied!
调用 make 函数新建一个 slice,底层调用的是 makeslice 函数,返回的是 slice 结构体:
1
func
makeslice
(
et
*
_type
,
len
,
cap
int
)
slice
Copied!
因此我们可以通过 unsafe.Pointer 和 uintptr 进行转换,得到 slice 的字段值。
1
func
main
()
{
2
s
:=
make
([]
int
,
9
,
20
)
3
var
Len
=
*
(
*
int
)(
unsafe
.
Pointer
(
uintptr
(
unsafe
.
Pointer
(
&
s
))
+
uintptr
(
8
)))
4
fmt
.
Println
(
Len
,
len
(
s
))
// 9 9
5
6
var
Cap
=
*
(
*
int
)(
unsafe
.
Pointer
(
uintptr
(
unsafe
.
Pointer
(
&
s
))
+
uintptr
(
16
)))
7
fmt
.
Println
(
Cap
,
cap
(
s
))
// 20 20
8
}
Copied!
Len,cap 的转换流程如下:
1
Len
:
&
s
=>
pointer
=>
uintptr
=>
pointer
=>
*
int
=>
int
2
Cap
:
&
s
=>
pointer
=>
uintptr
=>
pointer
=>
*
int
=>
int
Copied!
获取 map 长度
再来看一下上篇文章我们讲到的 map:
1
type
hmap
struct
{
2
count
int
3
flags
uint8
4
B
uint8
5
noverflow
uint16
6
hash0
uint32
7
8
buckets unsafe
.
Pointer
9
oldbuckets unsafe
.
Pointer
10
nevacuate
uintptr
11
12
extra
*
mapextra
13
}
Copied!
和 slice 不同的是,makemap 函数返回的是 hmap 的指针,注意是指针:
1
func
makemap
(
t
*
maptype
,
hint
int64
,
h
*
hmap
,
bucket unsafe
.
Pointer
)
*
hmap
Copied!
我们依然能通过 unsafe.Pointer 和 uintptr 进行转换,得到 hamp 字段的值,只不过,现在 count 变成二级指针了:
1
func
main
()
{
2
mp
:=
make
(
map
[
string
]
int
)
3
mp
[
"qcrao"
]
=
100
4
mp
[
"stefno"
]
=
18
5
6
count
:=
**
(
**
int
)(
unsafe
.
Pointer
(
&
mp
))
7
fmt
.
Println
(
count
,
len
(
mp
))
// 2 2
8
}
Copied!
count 的转换过程:
1
&
mp
=>
pointer
=>
**
int
=>
int
Copied!
Previous
如何实现字符串和byte切片的零拷贝转换
Next
goroutine 调度器
Last modified
2yr ago
Copy link
Contents
获取 slice 长度
获取 map 长度