I have a golang structure something like this:
type MyStruct struct {
Id string
}
and function:
func (m *MyStruct) id() {
// doing something with id here
}
Also I have another structure like this:
type MyStruct2 struct {
m *MyStruct
}
Now I have a function:
func foo(str *MyStruct2) {
str.m.id()
}
But I'm getting error in compile time:
str.m.id undefined (cannot refer to unexported field or method mypackage.(*MyStruct)."".id
How can I call this function correctly?
Thank you
From http://golang.org/ref/spec#Exported_identifiers:
An identifier may be exported to permit access to it from another
package. An identifier is exported if both:
- the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
- the identifier is declared in the package block or it is a field name or method name.
So basically only functions / variables starting with a capital letter would be usable outside the package.
Example:
type MyStruct struct {
id string
}
func (m *MyStruct) Id() {
// doing something with id here
}
//then
func foo(str *MyStruct2) {
str.m.Id()
}
If you change MyStruct.Id
to MyStruct.id
, you'll no longer be able to access it to initialize MyStruct2
, because, id
will be accessible only through its own package (which is first
package).
This is because MyStruct
and MyStruct2
are in different packages.
To solve that you can do this:
Package 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,
}
}
Package second
:
package second
// Import MyStruct's 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"),
})
}