Подтвердить что ты не робот

Вызов функции struct дает "не может ссылаться на неэкспортированное поле или метод"

У меня есть что-то вроде структуры:

type MyStruct struct {
    Id    string
}

и функция:

func (m *MyStruct) id() {
   // doing something with id here
}

Также у меня есть другая структура, подобная этой:

type MyStruct2 struct {
    m *MyStruct
}

Теперь у меня есть функция:

func foo(str *MyStruct2) {
    str.m.id()
}

Но я получаю сообщение об ошибке во время компиляции:

str.m.id undefined (cannot refer to unexported field or method mypackage.(*MyStruct)."".id

Как правильно вызвать эту функцию?

4b9b3361

Ответ 1

Из http://golang.org/ref/spec#Exported_identifiers:

Идентификатор может быть экспортирован, чтобы разрешить доступ к нему из другого пакет. Идентификатор экспортируется, если оба:

  • первый символ имени идентификатора - это письмо в верхнем регистре Юникода (класс Unicode "Lu" ); и
  • идентификатор объявляется в блоке пакета или это имя поля или имя метода.

Таким образом, в основном только функции/переменные, начинающиеся с прописной буквы, могут использоваться вне пакета.

Пример:

type MyStruct struct {
    id    string
}

func (m *MyStruct) Id() {
   // doing something with id here
}

//then

func foo(str *MyStruct2) {
    str.m.Id()
}

Ответ 2

Если вы измените MyStruct.Id на MyStruct.Id, вы больше не сможете получить к нему доступ для инициализации MyStruct2, потому что, id будет доступен только через свой собственный пакет (который представляет собой пакет first).

Это связано с тем, что MyStruct и MyStruct2 находятся в разных пакетах.


Чтобы решить это, вы можете сделать это:

Пакет first:

package first

type MyStruct struct {
    // `id` will be invisible outside of `first` package
    // because, it starts with a lowercase letter
    id string
}

// `Id()` is visible outside to `first` package 
// because, it starts with an uppercase letter
func (m *MyStruct) Id() string {
  return m.id
}

// Create a constructor function to return `*MyStruct`
func NewMyStruct(id string) *MyStruct {
    return &MyStruct{
        id: id,
    }
}

Пакет second:

package second

// Import MyStruct package
import "first"

type MyStruct2 struct {
    // If you don't use `m` here as in your question, 
    // `first.MyStruct` will be promoted automatically.
    //
    // So, you can reach its methods directly, 
    // as if they're inside `MyStruct2`
    *first.MyStruct
}

// You can use `Id()` directly because it is promoted
// As if, inside `MyStruct2`
func foo(str *MyStruct2) {
    str.Id()
}

// You can initialize `MyStruct2` like this:
func run() {
    foo(&MyStruct2{
        MyStruct: first.NewMyStruct("3"),
    })
}