go中的函数参数与指针,切片和接口{}混淆

时间:2018-08-30 14:53:20

标签: pointers go slice go-interface

我一直在学习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)

}

运行此代码时,它将打印包含Business.Name为Pizza 0到9的10个业务结构的列表。我了解在我的示例中,我的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为什么不同?

1 个答案:

答案 0 :(得分:2)

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

  

对于复合对象,使用以下规则递归地打印元素,如下所示:

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的十六进制值。