Invoking struct function gives "cannot refer to unexported field or method"

huangapple go评论142阅读模式
英文:

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:

为了允许从另一个包中访问,标识符可以被导出。如果满足以下两个条件,则标识符被导出:

  1. 标识符名称的第一个字符是Unicode大写字母(Unicode类别“Lu”);
  2. 标识符在包块中声明,或者它是字段名或方法名。

因此,只有以大写字母开头的函数/变量才能在包外使用。

示例:

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包来访问。
  • 原因是:MyStructMyStruct2位于不同的包中。

解决这个问题的方法如下:

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: the first package.
  • Because: MyStruct and MyStruct2 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"),
	})
}

huangapple
  • 本文由 发表于 2014年6月30日 18:22:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/24487943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定