为什么可以导出私有类型

时间:2016-07-23 12:05:11

标签: variables go types scope

这样想:

package first

type person struct {
    Name string
}

var Per = person{
    Name: "Jack",
}

并在主程序包中

package main

import "first"
import "fmt"

func main(){
    o := first.Per
    fmt.Println(o)
}

上面的工作,我们可以看到第一个包中的变量在外面是可见的,但它的类型不是,但它没有给出错误?以及如何在包装外使用它?

2 个答案:

答案 0 :(得分:3)

没关系:

  

导出的标识符:

     

可以导出标识符以允许从另一个标识符访问它   包。如果两者都导出标识符:

     
      
  • 标识符名称的第一个字符是Unicode大写   字母(Unicode类“Lu”);和
  •   
  • 标识符在。中声明   包块或它是字段名称或方法名称。所有其他   标识符不会导出。
  •   

参考:https://golang.org/ref/spec

甚至你可以使用Getters:

  

Go不为getter和setter提供自动支持。有   自己提供吸气剂和制定者并没有错,而且确实如此   通常适合这样做,但它既不是惯用的,也不是必需的   将Get放入getter的名字。如果您有一个名为owner的字段   (小写,未导出),getter方法应该称为Owner   (大写,导出),而不是GetOwner。使用大写名称   export提供了用于区分字段和方法的钩子。一个   如果需要,setter函数可能会被称为SetOwner。两个名字   在实践中读得很好:

owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}  

参考:https://golang.org/doc/effective_go.html

所以,如果您不想导出Name,请将其设为小写,例如此工作示例代码并使用Getter / Setter:

package first

type person struct {
    name string
}

var Per = person{
    name: "Jack",
}

func (p *person) SetName(name string) {
    p.name = name
}

func (p *person) Name() string {
    return p.name
}

main.go(带注释输出):

package main

import "first"
import "fmt"

func main() {
    person := first.Per
    fmt.Println(person.Name()) //Jack
    person.SetName("Alex")
    fmt.Println(person.Name()) //Alex
}

另一个用例:

答案 1 :(得分:1)

基本上,它是单身人士模式。该软件包导出person的单个实例,但由于该类型是私有的,因此您无法创建另一个实例。

更好的实现是导出一个返回私有类型的单例实例的函数。在第一次调用时,它将以线程安全的方式创建实例。

var (
    p    *person
    once sync.Once
)

type person struct {
    Name string
}

func Per() *person {
    once.Do(func() {
        p = &person{
            Name: "Jack",
        }
    })

    return p
}

sync.Once允许您只执行一段代码,即使多个goroutine正在尝试执行它。