English 中文(简体)
Go中的切片型铸造
原标题:Slice type casting in Go
  • 时间:2023-06-25 00:40:51
  •  标签:
  • go

I m quite new to Go coming from C++ background and have stumbled upon some weird issue. Here s the code:

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])
}

此代码失败的原因如下:

运行时错误:growtslice:len超出范围

例如,如果我将演员阵容更改为:

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

上面的代码工作得很好。

I understand that this is a cast to an array pointer and array must have constant size, but how to cast it to pointer to a slice then?

更令人困惑的是,可以采用切片的地址并将其分配给指针,如下所示:

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

And this time everything will work despite the fact that the type of pointer is the same type that i was casting unsafe pointer to in the first example. Can someone help to understand what s exactly going on here?

问题回答

一些背景:切片标头包含指向支持数组、长度和容量的指针。

问题第一部分中的代码将切片标头转换为指向切片标头的指针。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

我希望这能有所帮助。





相关问题
minimum work size of a goroutine [closed]

Does anyone know approximately what the minimum work size is needed in order for a goroutine to be beneficial (assuming that there are free cores for the work to be offloaded to)?

How do you get the terminal size in Go?

How do I get the terminal size in Go. In C it would look like this: struct ttysize ts; ioctl(0, TIOCGWINSZ, &ts); But how to i access TIOCGWINSZ in Go

What do you use to write Go [closed]

I know its a bit too early, but I ve been trying out Go (Google s Programming Language) and its kindof annoying to write code in gedit. So, my question: What do you use to experiment with Go?

Shared memory vs. Go channel communication

One of Go s slogans is Do not communicate by sharing memory; instead, share memory by communicating. I am wondering whether Go allows two different Go-compiled binaries running on the same machine to ...

Embedding instead of inheritance in Go

What is your opinion of this design decision? What advantages does it have and what disadvantages? Links: Embedding description

热门标签