Golang Go语言中 求大佬们看一下,通过指针强行转换类型,运行时会不会被教育.

发布于 1周前 作者 nodeper 来自 Go语言

有个非常大的结构而且是数组. 走 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) }


Golang Go语言中 求大佬们看一下,通过指针强行转换类型,运行时会不会被教育.

更多关于Golang Go语言中 求大佬们看一下,通过指针强行转换类型,运行时会不会被教育.的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

17 回复

就这个例子来讲,直接指针转换可以省去内存分配和拷贝,写法也更方便,但是要注意juDianUpdateTeamReqteamData指向同一片内存了,它们是会相互影响的,小心不要出现内存竞争。

更多关于Golang Go语言中 求大佬们看一下,通过指针强行转换类型,运行时会不会被教育.的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


#1 感谢回复. juDianUpdateTeamReq这个是 grpc 返回的,所以不用担心内存竟争

teamData 是否有被垃圾回收的风险?

https://go.dev/play/p/q3gwp2mERvj

这边有个详细一点的例子.

肯定是未定义行为,但是实践上应该没太大问题。

你既然有内存中的 juDianUpdateTeamReq 了,可以对它任意读写,转换成 TeamData 有啥意义呢?

不知大直接这样定义行不行 https://go.dev/play/p/phb2AxTdvyN

#4 因为要通过另一套结构返回给别的接口. 那个接口定义的 TeamData


#5 这样不满足我的需求. grpc 的结构是通过 proto 自动生成的. teamdata 结构也是自动生成的 是两套系统

对内存细节没理解清楚的话,不要乱用 unsafe

为什么不用最简单的写法呢

<br> teamData := TeamData{<br> Id: <a target="_blank" href="http://juDianUpdateTeamReq.Id" rel="nofollow noopener">juDianUpdateTeamReq.Id</a>,<br> // CurHp: 0,<br> // TotalHp: 0,<br> }<br> fmt.Println("teamData", &amp;teamData)<br>

string 本身就是个 fat pointer

#8 是这样的,这个只是示例结构.实际结构 都是数组,而且字段非常多.

所以用 unsafe 是为了减少内存分配.并且提高性能.

  • 过早优化是万恶之源
    - 不要滥用指针 包括指针数组 减轻 GC 的负担
    - 你计算过这个 struct 的字节大小吗

#11 > 过早优化是万恶之源

大佬说的太对了. 只是一个一个字段的赋值也是很麻

指针数组倒是没有用,.另外这 proto-go-gen 生成的结构都是指针,在 issue 查了一下,说是就是这样设计的.


一个 struct 大概 10-30 个左右的字段吧

一个 struct 大概 10-30 个左右的字段
常见的 数字 string slice map 类型,都很小
这样一个 struct 也就几十 /上百字节

slice []MyStruct 本身也是胖指针,没记个字节
数组 [n]MyStruct 的大小是 n * MyStruct 大小

这些在栈上传递都很快的

自己用 unsafe 处理指针,全靠自己记住内存布局,编译器帮不上忙

如果源 struct 后面有调整,旧代码也不会报错,可能会得到莫名其妙的结果
而且这种代码搜索和修改也很麻烦

#14

写了个结构体大小的比较.计算不对直接 panic, 后面的事后面再说 哈哈

不能只比较大小的

瞎玩 unsafe 是作死行为

在Golang(Go语言)中,通过指针强行转换类型是一种非常危险且不推荐的做法。这种操作在编译时可能不会报错,但在运行时很可能导致未定义行为,甚至程序崩溃,因此你提到的“被教育”实际上是指可能遇到严重的运行时错误。

Go语言是一种强类型语言,其类型系统旨在提供安全和可预测的行为。直接通过指针进行类型转换,会绕过Go的类型检查机制,从而可能引入难以调试的错误。

例如,如果你有一个int类型的指针,并试图将其转换为*struct类型的指针,然后解引用该指针以访问结构体成员,这将是未定义行为。因为intstruct在内存中的布局完全不同,这样的操作很可能导致内存访问违规。

如果你需要在Go中进行类型转换,应该使用显式的类型转换语句,但这些转换通常仅限于兼容类型之间。对于不兼容的类型,你应该重新考虑你的设计,使用接口(interface)或其他Go惯用的设计模式来实现所需的功能。

总之,通过指针强行转换类型在Go语言中是不安全的,应该避免这种做法。如果你确实需要进行类型相关的操作,请确保你的类型转换是安全的,并且符合Go语言的类型系统规范。这样可以避免运行时错误,提高代码的健壮性和可维护性。

回到顶部