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.
Related
I would like to access an internal property in a custom constructor, in my case it's a property from a superclass, like this:
type BaseRepository struct {
database mongo.Database
}
type PointRepository struct {
BaseRepository
pointCollection mongo.Collection
}
func NewPointRepository() *PointRepository {
pointCollection := ***self***.database.GetCollection("points")
pr := &PointRepository{
pointCollection: pointpointCollection,
}
}
As you can see, I need to access something like self to this approach works.
How can I workaround this situation?
There are no constructors or classes in Go.
PointRepository embeds BaseRepository, which has an unexported database field. Any function in the same package as BaseRepository can directly access the database field.
If you need to access that field from a function outside the package, you either have to export it, or you have to provide an exported getter method in BaseRepository.
Solution 1:
Add Set function for BaseRepository
Solution 2:
use unsafe package
type BaseRepository struct {
database string
}
type PointRepository struct {
BaseRepository
pointCollection string
}
baseRepository := &internel.BaseRepository{}
databasePointer := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(baseRepository))))
*databasePointer = "changed here"
fmt.Printf("%+v",baseRepository)
output:
&{database:changed here}
This is just an example, you should change the type of the field database.
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"
}
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
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
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
}