首页 > 解决方案 > 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函数收到了业务切片的副本,因此,business变量在我的主要功能中不受任何影响DoSomething

我接下来所做的就是将我的更改func DoSomething(b []Business)func DoSomething(b interface{}). 现在,当我尝试运行脚本时,出现运行时panic: reflect: Elem of invalid type on错误z := reflect.New(v.Type().Elem())

我注意到,DoSomething(b []Business)变量i == &[]. 但有了DoSomething(b interface{}),变量i == 0xc42000e1d0。为什么i在这两种情况下变量不同?

标签: pointersgoslicego-interface

解决方案


您的调试器最有可能使用(或至少遵循)fmt包的默认格式规则:

对于复合对象,使用这些规则以递归方式打印元素,布局如下:

struct:             {field0 field1 ...}
array, slice:       [elem0 elem1 ...]
maps:               map[key1:value1 key2:value2 ...]
pointer to above:   &{}, &[], &map[]

在您的第一种情况下i,它的值是 type *[]Business。因此,如果正在打印(或检查)的值是指向切片的指针,则将其打印为&[values].

在你的第二种情况下,i持有一个指向interface{}类型的值的指针*interface{}。打印这种类型的值时,使用默认%p格式,它只是将内存地址打印为前缀为 的十六进制值0x


推荐阅读