Vikram Chhipa
Vikram Chhipa

Reputation: 113

Why is it possible to export variable of private type

Think like this :

package first

type person struct {
    Name string
}

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

and in main package

package main

import "first"
import "fmt"

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

the above works, as we can see that the variable in first package was visible outside but it's type was not, but it gives no error? And how it can be useful outside package?

Upvotes: 1

Views: 2254

Answers (2)

user6169399
user6169399

Reputation:

it is fine:

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. All other identifiers are not exported.

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

and even you can use Getters:

Go doesn't provide automatic support for getters and setters. There's nothing wrong with providing getters and setters yourself, and it's often appropriate to do so, but it's neither idiomatic nor necessary to put Get into the getter's name. If you have a field called owner (lower case, unexported), the getter method should be called Owner (upper case, exported), not GetOwner. The use of upper-case names for export provides the hook to discriminate the field from the method. A setter function, if needed, will likely be called SetOwner. Both names read well in practice:

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

ref: https://golang.org/doc/effective_go.html

so if you do not want to export Name make it lower case, like this working sample codes and use 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 (with commented output):

package main

import "first"
import "fmt"

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

another use cases:

Upvotes: 2

creker
creker

Reputation: 9570

Essentially, it's a singleton pattern. The package exports a single instance of person but because the type is private you can't create another instance out of it.

Better implementation would be to export a function that returns a singleton instance of a private type. On first invocation it will create the instance in a thread-safe manner.

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 allows you to execute a piece of code only once even if multiple goroutines are trying to execute it.

Upvotes: 1

Related Questions