> I would never have imagined that you’re expected to make struct types public in order to return instances
You can return unexported ("private") instances; for example this is perfectly valid:
type unexport struct {
Str string
}
func (unexport) Method() string { return "export" }
func NewUnexport() unexport {
return unexport{Str: "asd"}
}
And you can get/set the exported Str field from another package without problems, as well as call the exported Method.
You don't even need to make an unexport package type and can use an anonymous struct or type declared in the function too, although you can't add any methods like this and is often cumbersome because you need to declare the anonymous struct more than one.
And, of course, you can make parts of a struct private by just not exporting them. It's really not all that different to how OOP languages work with public/private, except that visibility is dictated in the name itself.