Путаница с указателем, кусочками и интерфейсом {} в аргументах функции в go - PullRequest
0 голосов
/ 30 августа 2018

Я читал о том, как 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 of Pizza от 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 отличается в этих двух обстоятельствах?

1 Ответ

0 голосов
/ 30 августа 2018

Ваш отладчик, скорее всего, использует (или, по крайней мере, следует) правила форматирования по умолчанию для пакета 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.

...