混淆函数参数中的指针、切片和接口{}
Confusion with pointer, slices and interface{} in function arguments in go
我一直在阅读有关 Go 如何通过指针与值将参数传递给函数的信息。我一直在阅读有关接口类型的信息。而且我一直在篡改反射包。但显然,由于这里的示例代码,我仍然不明白它是如何工作的:
package main
import (
"reflect"
"fmt"
)
type Business struct {
Name string
}
func DoSomething(b []Business) {
var i interface{}
i = &b
v := reflect.ValueOf(i).Elem()
for c:=0 ;c<10; c++ {
z := reflect.New(v.Type().Elem())
s := reflect.ValueOf(z.Interface()).Elem()
s.Field(0).SetString("Pizza Store "+ fmt.Sprintf("%v",c))
v.Set(reflect.Append(v, z.Elem()))
}
fmt.Println(b)
}
func main() {
business := []Business{}
DoSomething(business)
}
当我 运行 这段代码时,它会打印一个包含 10 个业务结构的列表,Business.Name 是比萨饼 0 到 9。我明白在我的示例中,我的 DoSomething
函数接收到业务切片的副本,因此,无论 DoSomething
做什么,我的主函数中的 business
变量都不会受到影响。
我接下来所做的是将我的 func DoSomething(b []Business)
更改为 func DoSomething(b interface{})
。现在,当我尝试 运行 我的脚本时,我在 z := reflect.New(v.Type().Elem())
行得到了 panic: reflect: Elem of invalid type on
的 运行 时间错误
我注意到 DoSomething(b []Business)
变量 i == &[]
。但是有了 DoSomething(b interface{})
,变量 i == 0xc42000e1d0
。为什么变量 i
在这两种情况下不同?
您的调试器很可能使用(或至少遵循)fmt
包的默认格式化规则:
For compound objects, the elements are printed using these rules, recursively, laid out like this:
struct: {field0 field1 ...}
array, slice: [elem0 elem1 ...]
maps: map[key1:value1 key2:value2 ...]
pointer to above: &{}, &[], &map[]
在您的第一种情况下,i
拥有类型 *[]Business
的值。因此,如果要打印(或检查)的值是指向切片的指针,则它会打印为 &[values]
.
在第二种情况下,i
持有一个指向 interface{}
值的指针,该值的类型为 *interface{}
。打印这种类型的值时,使用默认的 %p
格式,它只是将内存地址打印为前缀为 0x
.
的十六进制值
我一直在阅读有关 Go 如何通过指针与值将参数传递给函数的信息。我一直在阅读有关接口类型的信息。而且我一直在篡改反射包。但显然,由于这里的示例代码,我仍然不明白它是如何工作的:
package main
import (
"reflect"
"fmt"
)
type Business struct {
Name string
}
func DoSomething(b []Business) {
var i interface{}
i = &b
v := reflect.ValueOf(i).Elem()
for c:=0 ;c<10; c++ {
z := reflect.New(v.Type().Elem())
s := reflect.ValueOf(z.Interface()).Elem()
s.Field(0).SetString("Pizza Store "+ fmt.Sprintf("%v",c))
v.Set(reflect.Append(v, z.Elem()))
}
fmt.Println(b)
}
func main() {
business := []Business{}
DoSomething(business)
}
当我 运行 这段代码时,它会打印一个包含 10 个业务结构的列表,Business.Name 是比萨饼 0 到 9。我明白在我的示例中,我的 DoSomething
函数接收到业务切片的副本,因此,无论 DoSomething
做什么,我的主函数中的 business
变量都不会受到影响。
我接下来所做的是将我的 func DoSomething(b []Business)
更改为 func DoSomething(b interface{})
。现在,当我尝试 运行 我的脚本时,我在 z := reflect.New(v.Type().Elem())
panic: reflect: Elem of invalid type on
的 运行 时间错误
我注意到 DoSomething(b []Business)
变量 i == &[]
。但是有了 DoSomething(b interface{})
,变量 i == 0xc42000e1d0
。为什么变量 i
在这两种情况下不同?
您的调试器很可能使用(或至少遵循)fmt
包的默认格式化规则:
For compound objects, the elements are printed using these rules, recursively, laid out like this:
struct: {field0 field1 ...} array, slice: [elem0 elem1 ...] maps: map[key1:value1 key2:value2 ...] pointer to above: &{}, &[], &map[]
在您的第一种情况下,i
拥有类型 *[]Business
的值。因此,如果要打印(或检查)的值是指向切片的指针,则它会打印为 &[values]
.
在第二种情况下,i
持有一个指向 interface{}
值的指针,该值的类型为 *interface{}
。打印这种类型的值时,使用默认的 %p
格式,它只是将内存地址打印为前缀为 0x
.