Go语言 围棋中的片型铸造

qxgroojn  于 2023-06-27  发布在  Go
关注(0)|答案(1)|浏览(91)

我是一个刚接触Go的C++背景的新手,偶然发现了一些奇怪的问题。代码如下:

package main

import (
"fmt"
"unsafe"
)

func main() {
     arr := []string { "one", "two", "three" }
     address := unsafe.Pointer(&arr)
     addPtr := (*[]string)(unsafe.Pointer(*(*uintptr)(address)))
     fmt.Println((*addPtr)[0])
}

此代码失败,并显示:
运行时错误:growslice:len超出范围
例如,如果我将类型转换为:

addPtr := (*[0]string)(unsafe.Pointer(*(*uintptr)(address)))

上面的代码工作得很好。
我理解这是一个转换到数组指针和数组必须有恒定的大小,但如何转换它到一个切片的指针呢?
更令人困惑的是,可以像这样获取slice的地址并将其分配给指针:

func main() {
     arr := []string { "one", "two", "three" }
     var arrPtr *[]string = &arr
     fmt.Println((*arrPtr)[0])
}

这一次,尽管指针的类型与我在第一个例子中强制转换的不安全指针的类型相同,但一切都将正常工作。有人能帮我弄明白到底发生了什么吗?

nwo49xxi

nwo49xxi1#

一些背景:切片头包含指向后备数组的指针、长度和容量。
问题的第一部分中的代码将切片头转换为指向切片头的指针。go vet命令警告问题中的代码可能是对unsafe.Pointer的误用。
通过删除额外的解引用操作进行修复,以便代码从指向切片头的指针转换为指向切片头的指针。

arr := []string{"one", "two", "three"}
address := unsafe.Pointer(&arr)
addPtr := (*[]string)(unsafe.Pointer((*uintptr)(address)))
fmt.Println((*addPtr)[0]) // prints one

不需要转换为 *uintptr。简化为:

arr := []string{"one", "two", "three"}
address := unsafe.Pointer(&arr)
addPtr := (*[]string)(unsafe.Pointer(address))
fmt.Println((*addPtr)[0]) // prints one

不需要不安全的恶作剧。简化为:

arr := []string{"one", "two", "three"}
addPtr := &arr
fmt.Println((*addPtr)[0]) // prints one

使用以下代码将切片的后台数组指针转换为数组指针。代码是脆弱的,因为它假定切片头的第一个字是指向后备数组的指针。

arr := []string{"one", "two", "three"}
address := unsafe.Pointer(&arr)
addPtr := (*[1]string)(unsafe.Pointer(*(*uintptr)(address)))
fmt.Println((*addPtr)[0]) // prints one

不需要前面代码段中的uintptr转换。简化为:

arr := []string{"one", "two", "three"}
address := unsafe.Pointer(&arr)
addPtr := (*[]string)(address)
fmt.Println((*addPtr)[0]) // prints one

希望这能帮上忙。

相关问题