Imported struct to be used as anonymous field - go

So I'm trying to write a few Go files such that there is a public facing package and an internal package.
In the public facing package, there is a struct that is nearly identical (missing one field) to an internal struct.
I thought of using an anonymous field in the internal struct, but it doesn't seem to play nicely.
Example:
public/public.go:
package public
type PublicStruct struct {
Field1 bool `json:"fetchStats"`
}
data/data.go
package data
import publicData "public"
type InternalStruct struct {
publicData.PublicStruct
Field2 bool `json:"includeHidden:`
}
filter/filter.go:
package filter
import "data"
func test() {
tmp := data.InternalStruct{Field1: true, Field2: false}
}
main.go:
package main
import "filter"
import "data"
func main() {
var tmp data.InternalStruct
tmp.Field1 = true
tmp.Field2 = true
filter.Test()
}
Expected: no issues
Result: filter/filter.go:6: unknown data.InternalStruct field 'Field1' in struct literal
Why does this not work and what should I do to make it work (I'm currently using the duplicate parameters in both structs approach)?
PS: I don't know how to test this in go playground since it involves multiple files.

The issue is that field1 isn't being exported by the public package as it's name is lower cased. If it were instead Field1 then you could access it inside the internal package like MyInternalStructInstance.Field1
EDIT - Addresses OP's update;
The syntax you're using for initilization in your main is just wrong. It should be:
tmp := InternalStruct{PublicStruct: PublicStruct{Field1: true}, Field2: false}
It has nothing to do with the packages or imported vs exported. It can easily be tested on the playground, a complete example is here; https://play.golang.org/p/tbCqFeNStd

Related

Export imports with Golang

Not sure if this is impossible with Golang. With Node.js, I would do it like so:
import * as person from './person';
export {person};
with Golang I have models.go:
package models
import (
"huru/models/person"
)
is it possible to export person from this models.go file, in a person namespace like with TypeScript/node.js?
[I]s it possible to export person from this models.go file, in a person namespace like with TypeScript/node.js?
No.
You cannot just pass through a complete package. You can pass through different types by making your own types based on them. If there was a person.Person:
package models
import (
"huru/models/person"
)
type Person person.Person
//or
type EmbeddedPerson struct{
person.Person
additional string
}
This has the advantage of allowing you to add your own functions
func (p Person) CustomFunc() {}
Here is a playground link that shows some of the nuances of this: https://play.golang.org/p/1aLOcmsXHV2
#MrCholo there is a little difference in golang concept here. The golang structs available under namespace scoped.
Like as per example
package models
// struct name should starts with Capital letter to export
type Person struct {
Name string
age int
}
The Person struct will be available in all files scoped under same namespace(ex. models). You don't need to import that.
But if you would like to access outside the models namespace you'll have to import the package models and access the Person object using that.
ex.
package anotherpackage
import (
"<path to models>/models"
)
var perObj models.Person // here is how you can access the Person struct
Let me know if it's still not clear to you.
No.
You can use like this, for example custom log
package customLog
import "log"
func Print(args ...interface{}) {
log.Print(args)
}
package example
func some() {
customLog.Print("hi babay")
}
Yes, We can export struct from file to another file(or package) like other languages.
person.go
package models
// struct name should starts with Capital letter to export
type Person struct {
Name string
age int
}
If the importing file is in the same package(models), then no need to import. Straight away you can use like this:
details.go
package models
var perObj Person
func abc() {
perObj.Name = "xyz"
}
If the importing file is in some other package, then import models package.
businesslogic.go
package logic
import (
"../../models"
)
var perObj Person
func abc() {
perObj.Name = "xyz"
}

golang initializing struct with embedded template: too few values in struct initializer

I'm trying to initialize a golang struct with an embedded template. Since templates have no fields, I would expect that assigning the correct number of variables to a constructor would work, but instead the compiler complains that
main.go:17:19: too few values in struct initializer
package main
import "fmt"
type TestTemplate interface {
Name() string
}
type TestBase struct {
name string
TestTemplate
}
func New(name string) *TestBase {
return &TestBase{name} // This fails
//return &TestBase{name: name} // This works
}
func (v *TestBase) Name() string {
return v.name
}
func main() {
fmt.Println(New("Hello"))
}
https://golang.org/ref/spec#Struct_types
An embedded field is still a field, the name of which is derived from its type, therefore TestBase has actually two fields and not one, namely name and TestTemplate.
This compiles just fine:
var t *TestBase
t.TestTemplate.Print()
So when initializing TestBase you either specify the field names or you initialize all fields.
These all compile:
_ = &TestBase{name, nil}
_ = &TestBase{name: name}
_ = &TestBase{name: name, TestTemplate: nil}
_ = &TestBase{TestTemplate: nil}
It looks like (as far as general concepts go) you're confusing interfaces with composition (which is kind of how Go approaches the whole inheritance question.
This post might be helpful for you: https://medium.com/#gianbiondi/interfaces-in-go-59c3dc9c2d98
So TestTemplate is an interface.
That means that the struct TestBase will implement the methods (whose signature is) defined in the interface.
You should implement Print for TestBase.
But in anycase the error you're getting is because when you initialize a struct with no field names specified, it expects all the field names to be entered, see
https://gobyexample.com/structs
So remove the composition TestTemplate from the struct (and implement the method defined in the interface instead), and it should work.
Also, FYI, the Stringer interface with String method is what fmt.Println expects to print an arbitrary struct (not a Print method) see: https://tour.golang.org/methods/17

exported field in unexported struct

Example:
type myType struct {
foo []float64
Name string
}
myType is not exported, but Name field in it is exported.
Does this make sense to do this? Is that considered a bad practice?
I have something like this, and it compiles fine.
I can access the Name field if I create an exported array of myType:
var MyArray []myType = {... some initialization }
fmt.Println(MyArray[0].Name) // Name is visible and it compiles
It is perfectly valid to have unexported structs with exported fields. If the type is declared in another package, the declaration var MyArray []myType would be a compile-time error.
While it is perfectly valid to have an exported function with an unexported return type, it is usually annoying to use. The golint tool also gives a warning for such cases:
exported func XXX returns unexported type pname.tname, which can be annoying to use
In such cases it's better to also export the type; or if you can't or don't want to do that, then create an exported interface and the exported function should have a return type of that interface, and so the implementing type may remain unexported. Since interfaces cannot have fields (only methods), this may require you to add some getter methods.
Also note that in some cases this is exactly what you want: unexported struct with exported fields. Sometimes you want to pass the struct value to some other package for processing, and in order for the other package to be able to access the fields, they must be exported (but not the struct type itself).
Good example is when you want to generate a JSON response. You may create an unexported struct, and to be able to use the encoding/json package, the fields must be exported. For example:
type response struct {
Success bool `json:"success"`
Message string `json:"message"`
Data string `json:"data"`
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
resp := &response{
Success: true,
Message: "OK",
Data: "some data",
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
// Handle err
}
}

Private embedded struct when importing a struct from another package

I have a project which relies on a struct imported from another package, which I will call TheirEntity.
In the example below, I (ahem) embed TheirEntity in MyEntity, which is an extension of TheirEntity, with added functionality.
However, I don't want to export TheirEntity in the MyEntity structure, as I would rather the consumer not access TheirEntity directly.
I know that Go embedding is not the same as inheritance in classical OOP, so maybe this is not the correct approach, but is it possible to specify embedded structs as "private", even if they are imported from another package? How might one achieve the same thing in a more idiomatic fashion?
// TheirEntity contains functionality I would like to use...
type TheirEntity struct {
name string
}
func (t TheirEntity) PrintName() {
fmt.Println(t.name)
}
func NewTheirEntity(name string) *TheirEntity {
return &TheirEntity{name: name}
}
// ... by embedding in MyEntity
type MyEntity struct {
*TheirEntity // However, I don't want to expose
// TheirEntity directly. How to embed this
// without exporting and not changing this
// to a named field?
color string
}
func (m MyEntity) PrintFavoriteColor() {
fmt.Println(m.color)
}
func NewMyEntity(name string, color string) *MyEntity {
return &MyEntity{
TheirEntity: NewTheirEntity(name),
color: color,
}
}
Since the question was asked, Go saw the addition of type aliases to the language with the 1.9 release in 2017. It turns out that, through an unconventional use of type aliases, you can have your cake and eat it too!
First, declare an unexported alias for the third-party type you wish to embed in your struct:
type theirEntity = TheirEntity
Then, simply embed that alias instead of the original type:
type MyEntity struct {
*theirEntity
color string
}
(Playground)
[I]s it possible to specify embedded structs as "private", even if they are imported from another package?
No.
How might one achieve the same thing in a more idiomatic fashion?
By not-embedding but making it a unexported named field.
Like this:
type MyEntity struct {
*privateTheirEntity
}
type privateTheirEntity struct {
*TheirEntity
}

Subclassing an object in a different package in golang

I'm trying to create a base object for all my structs in golang. For some reason I can't get it to work when the new object I create is in a different package. It works fine when they are in the same package/folder.
e.g. a base class for all objects
package Test
type BaseObject struct {
base interface{}
}
---- Sub Folder Test\Stuff ---
create a new TestObject which subclasses BaseObject
package Stuff
import Test "Test"
type TestObject struct{
Test.BaseObject
}
func (this *TestObject)DoSomething(){
any reference to this.base or this.BaseObject.base fails!!!
}
--- In the same folder, everthing works ---
package Test
type TestObject struct{
BaseObject
}
func (this *TestObject)DoSomething(){
any reference to this.base works fine??
}
You can't reference hidden or "private" fields in structs outside their packages.
If you would just do:
type BaseObject struct {
Base interface{}
}
Base will be exposed or "public" in the context of other packages, and everything will work.

Resources