Последствия определения структуры внутри функции vs снаружи?

Есть ли какие-либо последствия (GC churn, performance, or other) для определения struct внутри функции, если она определена вне? Например:

type Outside struct {
  Foo string `json:"foo"`
}

func SomeFunc(b []byte) error {
  outside := Outside{}

  if err := json.NewDecoder(b).Decode(&outside); err != nil {
    return err
  }

  ...
}

против.

func SomeFunc(b []byte) error {

  type inside struct {
    Foo string `json:"foo"`
  }

  if err := json.NewDecoder(b).Decode(&inside); err != nil {
    return err
  }

  ...
}

Будут ли ситуации, когда одна из них предпочтительнее другой?

Ответ 1

Для меня главный недостаток типа, определенного в функции, заключается в том, что вы не можете определять методы для этого типа.

Посмотрите этот пример https://play.golang.org/p/cgH01cRwDv6:

package main

import (
    "fmt"
)

func main() {
    type MyType struct {
        Name string
    }

    // You cannot define a method on your type
    // defined in a function, can you?

    func (m MyType) String() string {
      return m.Name
    }

    m := MyType{Name: "Hello, World!"}
    fmt.Println(m)
}

В приведенном выше примере произойдет сбой с ошибкой prog.go:15:27: expected ';', found 'IDENT' string (and 1 more errors).

Ответ 2

Нет разницы в производительности - это только разница в объеме (т.е. где видение типа можно увидеть). Если вам нужен только тип внутри одной функции, это прекрасно, чтобы определить его там.

Как отмечали другие, если вы определяете тип на уровне пакета (т.е. вне функции) с именем, начинающимся с прописной буквы, он будет экспортироваться (т.е. видимым вне пакета). Если имя не начинается с заглавной буквы, оно будет отображаться только внутри пакета.

Ответ 3

Мое понимание - это разница только в доступности. Структура, определенная начиная с буквы верхнего регистра, будет экспортироваться, то есть к ней можно получить доступ из других пакетов. Структуру, определенную начиная с буквы нижнего регистра, можно получить из всего, что находится внутри одного и того же пакета, но не извне. Структуру, определенную в функции в строке, можно получить или инициализировать только этой функцией.

Ответ 4

Существует очевидная проблема определения области видимости при объявлении чего-либо внутри тела функции, а не вне его.

Но также в первом примере вы объявляете тип вне тела функции, обозначаемый символом Outside.

В вашем втором примере вы объявляете переменную, обозначенную символом внутри. Это имеет буквальный тип описанной структуры.

Обратите внимание, что в первом примере вы можете использовать символ Outside для ссылки на любые переменные типа Outside.

В вашем втором примере нет символа для ссылки на тип переменной, вызываемой внутри. Это связано с тем, что тип этой переменной обозначается с помощью анонимной структуры.

Ответ 5

Для меня я однажды определил структуру внутри функции для сортировки байта json [] в экземпляре структуры и извлечения сообщения из экземпляра.

Очевидно, что не требуется определять структуру. Я мог бы извлечь сообщение, перенаправив байтовый массив json в интерфейс {}, а затем привести его рекурсивно, чтобы получить требуемое сообщение.

Определив структуру, извлечение сообщения становится очень простым :)

    var errDetail struct {
        Message string 'json:"message"'
        Success bool   'json:"success"'
    }

    json.Unmarshal(*bytes, &errDetail)

    if errDetail.Message == "" {
        fmt.Println("error message is not present")
        return nil
    }
    return errDetail.Message