Вызов функции 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
Как правильно вызвать эту функцию?
Ответы
Ответ 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"),
})
}