Go Packages, Exported and Unexported Identifiers

Go is different from a lot of languages in how it handles making package identifiers available to other packages. In other languages like C# and Java you have the notions of public, private, protected, internal etc that control the visibility of functions, interfaces, variables, in Go you have the notion of exported or unexported.

Some people incorrectly call this public or private when referring to Go packages, but that is not the case as we will see in a bit, an unexported identifier can still be used outside of a package, so it would be incorrect to call it private.

//TODO: https://talks.golang.org/2014/organizeio.slide\#5

Exporting an identifier

In Go an identifier is available outside of the package it is declared in if the identifier starts with a capital letter, it it starts with a lowercase letter, it is unexported. For example, in the code below, we have a type called Postgres in the database package, it starts with an uppercase letter, so we can access it from the main package:

main.go

package main

import (
    "github.com/markdaws/getting-started-with-go/database"
)

func main() {
    p := database.Postgres{ Address: "192.168.0.1" }
    _ = p
}

database.go

package database

type Postgres struct{
    Address string
}

If we change the Postgres type to be "postgres" and try to compile, you will get an error.

Using unexported identifiers

As mentioned before it is wrong to think of Go's package mechanism as public/private, since we can still access an unexported type, for example if we use the short initialization syntax so that we don't explicitly declare a type we can do the following:

package database

type postgres struct {
    Address string
}

func NewPostgres(address string) postgres {
    return postgres{Address: address}
}

main.go

func main() {
    p := database.NewPostgres("192.168.0.1")
    fmt.Println(p.Address)
}

Here you see we can return the unexported struct from an exported function and reference it's field.

Struct Fields

The fields of a struct work in the same way, if the field starts with an uppercase letter it will be exported and available outside the package, otherwise it won't.

You should think of exported identifiers as the API to your package, only export the identifiers that you really need to let other developers access and keep all of the internal implementation details unexported.

embedded acess

//naming conventions for interfaces

results matching ""

    No results matching ""