I was testing go's type visibility and received unexpected behavior when I exposed a private type through a public function:
package pak
type foo struct { // shoudn't be visible to any other package than pak
Bar string
}
func NewFoo(str string) *foo {
return &foo{str}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package main
import (
"fmt"
"pak"
)
func main() {
// these lines should be equivalent...
var f = pak.NewFoo("Hello, World!") // this works fine...
var f *pak.foo = pak.NewFoo("Hello, World!") // ERROR: cannot refer to unexported name pak.foo
fmt.Printf("%T
", f)
fmt.Printf("%s
", f.Bar) // how does it know about .Bar, if it can't see pak.foo?
}
Without explicitly declaring the type of f
, it prints:
*pak.foo
Hello, World!
but with *pak.foo
it fails to compile.
Why doesn't it fail in both cases?
(this question is sort of related, but it does not answer this question)
The valid statement
var f = pak.NewFoo("test")
gives you an anonymous, hidden address for the struct
foo
. You can't use it to read from or write to the struct
foo
outside the pak
package. You can, and usually will, use it to call a pak
package method. For example,
p := f.PakMethod()
The invalid statement
var f *pak.foo = pak.NewFoo("test")
attempts to obtain the address of the struct
foo
. If permitted, this would allow you to read from and write to the struct
foo
outside the pak
package.