有个非常大的结构而且是数组. 走 grpc 返回结果要一个一个赋值
想直接通过指针转换过来, 看起来可行 但是怕运行时被教育
https://go.dev/play/p/v5vJ53sXiEs
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"sync"
"unsafe"
)
// NoUnkeyedLiterals can be embedded in a struct to prevent unkeyed literals.
type NoUnkeyedLiterals struct{}
// DoNotCompare can be embedded in a struct to prevent comparability.
type DoNotCompare [0]func()
// DoNotCopy can be embedded in a struct to help prevent shallow copies.
// This does not rely on a Go language feature, but rather a special case
// within the vet checker.
//
// See https://golang.org/issues/8005.
type DoNotCopy [0]sync.Mutex
// Requirements:
// - The type M must implement protoreflect.ProtoMessage.
// - The address of m must not be nil.
// - The address of m and the address of m.state must be equal,
// even though they are different Go types.
type MessageState struct {
NoUnkeyedLiterals
DoNotCompare
DoNotCopy
// atomicMessageInfo *MessageInfo
}
type (
UnknownFields = unknownFieldsA // TODO: switch to unknownFieldsB
unknownFieldsA = []byte
)
type JuDianUpdateTeamReq struct {
state MessageState
sizeCache int32
unknownFields UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
CurHp uint64 `protobuf:"varint,2,opt,name=curHp,proto3" json:"curHp,omitempty"`
TotalHp uint64 `protobuf:"varint,3,opt,name=totalHp,proto3" json:"totalHp,omitempty"`
}
type TeamData struct {
Id string `json:"id,omitempty"`
CurHp uint64 `json:"curHp,omitempty"`
TotalHp uint64 `json:"totalHp,omitempty"`
}
func main() {
juDianUpdateTeamReq := &JuDianUpdateTeamReq{
Id: "team1",
CurHp: 100,
TotalHp: 200,
}
teamData := (*TeamData)(unsafe.Pointer(&juDianUpdateTeamReq.Id))
fmt.Println("teamData", teamData)
}
1
yicixin 2023-02-03 17:18:30 +08:00
就这个例子来讲,直接指针转换可以省去内存分配和拷贝,写法也更方便,但是要注意`juDianUpdateTeamReq`和`teamData `指向同一片内存了,它们是会相互影响的,小心不要出现内存竞争。
|
2
whitehack OP @yicixin #1 感谢回复. `juDianUpdateTeamReq`这个是 grpc 返回的,所以不用担心内存竟争
teamData 是否有被垃圾回收的风险? https://go.dev/play/p/q3gwp2mERvj 这边有个详细一点的例子. |
3
leonshaw 2023-02-04 10:57:28 +08:00
肯定是未定义行为,但是实践上应该没太大问题。
|
4
lysS 2023-02-06 15:17:15 +08:00
你既然有内存中的 juDianUpdateTeamReq 了,可以对它任意读写,转换成 TeamData 有啥意义呢?
|
5
lysS 2023-02-06 15:20:37 +08:00
不知大直接这样定义行不行 https://go.dev/play/p/phb2AxTdvyN
|
6
whitehack OP |
7
xuyang2 2023-02-08 11:22:45 +08:00
对内存细节没理解清楚的话,不要乱用 unsafe
|
8
xuyang2 2023-02-08 11:25:21 +08:00
为什么不用最简单的写法呢
``` teamData := TeamData{ Id: juDianUpdateTeamReq.Id, // CurHp: 0, // TotalHp: 0, } fmt.Println("teamData", &teamData) ``` |
9
xuyang2 2023-02-08 11:25:43 +08:00
string 本身就是个 fat pointer
|
10
whitehack OP |
11
xuyang2 2023-02-08 15:40:19 +08:00
- 过早优化是万恶之源
- 不要滥用指针 包括指针数组 减轻 GC 的负担 - 你计算过这个 struct 的字节大小吗 |
12
whitehack OP @xuyang2 #11 > 过早优化是万恶之源
大佬说的太对了. 只是一个一个字段的赋值也是很麻 指针数组倒是没有用,.另外这 proto-go-gen 生成的结构都是指针,在 issue 查了一下,说是就是这样设计的. 一个 struct 大概 10-30 个左右的字段吧 |
13
xuyang2 2023-02-08 16:25:30 +08:00
一个 struct 大概 10-30 个左右的字段
常见的 数字 string slice map 类型,都很小 这样一个 struct 也就几十 /上百字节 slice []MyStruct 本身也是胖指针,没记个字节 数组 [n]MyStruct 的大小是 n * MyStruct 大小 这些在栈上传递都很快的 |
14
xuyang2 2023-02-08 16:33:23 +08:00
自己用 unsafe 处理指针,全靠自己记住内存布局,编译器帮不上忙
如果源 struct 后面有调整,旧代码也不会报错,可能会得到莫名其妙的结果 而且这种代码搜索和修改也很麻烦 |
16
xuyang2 2023-02-08 18:27:33 +08:00
不能只比较大小的
瞎玩 unsafe 是作死行为 |