Golang中[]interface{}和interface{}转换相同变量c时为何行为不同?
Golang中[]interface{}和interface{}转换相同变量c时为何行为不同?
类型转换:为什么 []interface{} 和 interface{} 在转换同一个变量 c 时表现不同?
你做了什么?
在这个应用中,你可以看到 uint8 类型的 c 将值赋给 i 和 i2,并进行直接转换,这意味着你可以看到 uint8 类型的 c 被转换为 interface{},这始终是一个一致的地址,这在这里是可以理解的。
然后是第二个例子
这个例子再次使用了 uint8 类型的 c 将值赋给 i,此外,unsafe 包被转换为指针 p,用于修改 i 的值。在 fmt.Println© 中测试后,p 修改的值实际上影响了 c。fmt.Println© 的输出是 30,但通过 println 可以看到 c 的值是 20。这是因为 c 被转换为 []interface{} 类型传入 fmt.Println,并且当 uint8 进行 interface{} 转换时,它与 uint8 是相同的内存地址。
然后是第三个例子
package main
import (
"fmt"
"unsafe"
)
type ef struct {
_type unsafe.Pointer
data unsafe.Pointer
}
func main() {
var c uint32 = 20
var i interface{} = c
p := unsafe.Pointer(&i)
ptr := (*ef)(p)
p2 := (*int64)(ptr.data)
*p2 = 30
println(c)
fmt.Println(c)
}
将 c 改为 uint32 类型(不是 uint8 类型),你可以看到修改 p 的值不会影响 c,这当然是因为 c 在每次通过 interface{} 转换时地址解释不一致,因为 golang 是值拷贝的。
最后,当我们在 fmt.Println© 中添加任何值时,例如 fmt.Println(p, c),我们发现即使是 uint32 类型的 c 变量也被 p 修改,在第四个例子中打印出 30。
package main
import (
"fmt"
"unsafe"
)
type ef struct {
_type unsafe.Pointer
data unsafe.Pointer
}
func main() {
var c uint32 = 20
var i interface{} = c
p := unsafe.Pointer(&i)
ptr := (*ef)(p)
p2 := (*int64)(ptr.data)
*p2 = 30
println(c)
fmt.Println(p, c)
}
你期望看到什么?
在第四种情况下,当将 c 和其他参数转换为 interface{} 时,没有使用相同的内存地址。并且 fmt.Println© 的输出应该是 20。
你实际看到了什么?
我对 []interface{} 进行转换的规则感到困惑,为什么在转换 uint8 类型时会出现相同的地址,而其他类型则不会。
为什么 []interface{} 和 interface{} 在转换同一个变量 c 时表现不同?
非常感谢可能的答案。并将测试代码粘贴在下面:
package main
import (
"fmt"
"unsafe"
)
type ef struct {
_type unsafe.Pointer
data unsafe.Pointer
}
func main() {
var c uint32 = 20
var i interface{} = c
p := unsafe.Pointer(&i)
ptr := (*ef)(p)
p2 := (*int64)(ptr.data)
*p2 = 30
println(c) // output: 20
fmt.Println(p, c) // output: 0xc000014270 30
}
更多关于Golang中[]interface{}和interface{}转换相同变量c时为何行为不同?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中[]interface{}和interface{}转换相同变量c时为何行为不同?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个关于Go语言接口底层表示和内存布局的问题。关键区别在于值的大小和内存对齐方式。
package main
import (
"fmt"
"unsafe"
)
// 接口的底层表示(简化版)
type iface struct {
tab unsafe.Pointer
data unsafe.Pointer
}
func main() {
// 情况1: uint8(1字节)
var c1 uint8 = 20
var i1 interface{} = c1
println("uint8 - 直接存储在接口中")
println("c1地址:", unsafe.Pointer(&c1))
println("i1.data:", (*iface)(unsafe.Pointer(&i1)).data)
// 情况2: uint32(4字节)
var c2 uint32 = 20
var i2 interface{} = c2
println("\nuint32 - 需要额外分配内存")
println("c2地址:", unsafe.Pointer(&c2))
println("i2.data:", (*iface)(unsafe.Pointer(&i2)).data)
// 情况3: 验证修改
var i3 interface{} = c2
p := unsafe.Pointer(&i3)
ptr := (*iface)(p)
// 获取实际存储的值
if uintptr(ptr.data) == uintptr(unsafe.Pointer(&c2)) {
println("直接引用原变量")
} else {
println("复制到新内存位置")
// 修改复制的值
*(*uint32)(ptr.data) = 30
println("c2:", c2) // 仍然是20
println("i3:", i3) // 变为30
}
}
对于小值(通常≤指针大小),Go会直接将其存储在接口的data字段中。对于大值,会分配新内存并复制。fmt.Println接收...interface{},每个参数单独转换,可能产生不同的内存行为。

