英文:
Invoking struct function gives "cannot refer to unexported field or method"
问题
我有一个类似这样的结构:
type MyStruct struct {
Id string
}
和一个函数:
func (m *MyStruct) id() {
// 在这里处理id
}
还有另一个类似这样的结构:
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
如何正确调用这个函数?
英文:
I have a 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?
答案1
得分: 109
从http://golang.org/ref/spec#Exported_identifiers:
为了允许从另一个包中访问,标识符可以被导出。如果满足以下两个条件,则标识符被导出:
- 标识符名称的第一个字符是Unicode大写字母(Unicode类别“Lu”);
- 标识符在包块中声明,或者它是字段名或方法名。
因此,只有以大写字母开头的函数/变量才能在包外使用。
示例:
type MyStruct struct {
id string
}
func (m *MyStruct) Id() {
// 在这里对id进行操作
}
//然后
func foo(str *MyStruct2) {
str.m.Id()
}
英文:
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:
>
> 1. the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
> 2. 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()
}
答案2
得分: 9
如果你将MyStruct.Id
更改为MyStruct.id
:
- 你将无法通过初始化
MyStruct2
来访问它。 id
只能通过它自己的包——first
包来访问。- 原因是:
MyStruct
和MyStruct2
位于不同的包中。
解决这个问题的方法如下:
first
包:
package first
type MyStruct struct {
// `id`以小写字母开头,将在`first`包之外不可见
id string
}
// `Id()`以大写字母开头,对`first`包之外可见
func (m *MyStruct) Id() string {
return m.id
}
// 创建一个构造函数来返回`*MyStruct`
func NewMyStruct(id string) *MyStruct {
return &MyStruct{
id: id,
}
}
second
包:
package second
// 导入`MyStruct`的包
import "first"
type MyStruct2 struct {
// 如果你在这里不使用`m`,`first.MyStruct`将自动提升。
//
// 因此,你可以直接访问它的方法,就像它们在`MyStruct2`内部一样
*first.MyStruct
}
// 你可以直接使用`Id()`,因为它被提升了
// 就像在`MyStruct2`内部一样
func foo(str *MyStruct2) {
str.Id()
}
// 你可以这样初始化`MyStruct2`:
func run() {
foo(&MyStruct2{
MyStruct: first.NewMyStruct("3"),
})
}
以上是翻译好的内容。
英文:
If you change MyStruct.Id
to MyStruct.id
:
- You'll no longer be able to access it to initialize
MyStruct2
. id
will be accessible only through its own package: thefirst
package.- Because:
MyStruct
andMyStruct2
are in different packages.
To solve the problem 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"),
})
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论