How to make an object of a class and have getters for struct? - go

I have recently started working with golang so having difficulties understanding on how to achieve same thing which I am able to do it easily in Java or C#. I am trying to make an object of configmanager class and when the first time configmanager class is called, it should initialize all my configs and store it in memory in some struct object. And then I should have access to configmanager object and should be able to access all those configs from my main function using some getters maybe?
Below is my configmanager go class. It is very simple for now to make it easier to understand.
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/david/internal/utilities"
)
type ClientMetrics struct {
ClientMetrics []ClientMetric `json:"clientMetrics"`
}
type CustomerData struct {
Process []string `json:"Process"`
Mat []string `json:"Mat"`
}
type ClientMetric struct {
ClientID int `json:"clientId"`
CustomerData CustomerData `json:"customerData,omitempty"`
LegCustomer []int `json:"legCustomer"`
OtherIds []int `json:"otherIds,omitempty"`
CatID int `json:"catId,omitempty"`
}
func Init(root string) (err error) {
files, err := utilities.FindFiles(root, "process-data.json")
if err != nil {
return fmt.Errorf("cannot find process-data.json file: %v", err)
}
for _, file := range files {
body, err := ioutil.ReadFile(file)
if err != nil {
return fmt.Errorf("unable to read file: %v", err)
}
var auto ClientMetrics
json.Unmarshal(body, &auto)
}
return nil
}
And here is I use it in my main function - This is just basic code just to demonstrate what I am doing but this isn't production ready code.
package main
import (
"github.com/david/internal/config"
)
func main() {
root := "/home/Configurations"
config.Init(root)
//
}
In my above Init function, I find process-data.json file if it is there on the disk and then load it in memory by deserializing it into ClientMetrics object. Everything works fine as shown above.
Problem Statement
Since I am coming from Java and C# background, so my confusion is how can I make an object of configmanager class and how should I initialize all my configs during the first time when I call configmanager and also have access to ClientMetrics struct using some getters. In Java and C#, I used to have constructor where I initialize all these things and then have some getters to access the config. How should I do the same thing in golang.
My main confusion is do we have constuctors in go and how should I make getters to access struct object in my main function? I am just looking for better design in go and how should I do my above code in golang?
Update
I think I wasn't able to explain properly. I have X (let's suppose 5 for now) different json files in a folder and each of those json files needs to have their own struct because they are totally different json files. My configmanager file will be responsible to load all those 5 json files into their own struct and then I should be able to access all those 5 structs and their fields from the object of configmanager. All this should happen during the initialization of configmanager class when it is called for the first time.
Here is just an example where I have bunch of json files in their own corresponding folder (folderX). I have three categories of files (clientMap-*.json, dataMap-*.json, process-data.json) as shown below.
Products
├── folder1
│ ├── clientMap-123.json
│ ├── clientMap-987.json
│ ├── clientMap-7161.json
├── folder2
│ ├── dataMap-18271.json
│ ├── dataMap-12921.json
│ ├── dataMap-98121.json
└── folder3
├── process-data.json
Now I need to read all these files (clientMap-*.json, dataMap-*.json, process-data.json) in their own struct. And I should able to use configmanager class to get corresponding struct and their fields too after unmarshalling.
For example: Read clientMap-*.json files.
files, err := utilities.FindFiles(root, "clientMap-*.json")
// load all clientMap-*.json files in its own struct after unmarshalling
Similarly for dataMap-*.json files
files, err := utilities.FindFiles(root, "dataMap-*.json")
// load all dataMap-*.json files in its own struct after unmarshalling
Also for process-data.json files
files, err := utilities.FindFiles(root, "process-data.json")
// load all process-data.json files in its own struct after unmarshalling
My FindFiles method will find all the files even with regex like above. files variable is an array containing list of all files matching particular pattern. Now I can create ConfigManager struct type holding all other structs for my config but I am trying to find a solution which is easily extensible so that in future if I add any other json file category it should be able to extend easily. What is the correct way to solve this?

This question is hard to answer because you kind of forgot to ask one in a definitive way, so I will start my answer by extracting a question based on what you wrote. I believe we can do so from this:
Problem Statement
[...] my confusion is how can I make an object of configmanager class and how should I initialize all my configs during the first time when I call configmanager and also have access to ClientMetrics struct using some getters
I believe the real question here is "How do I separate the concern of reading and unmarshalling the files from the concern of storing the results for my program to use?".
It's common to separate concerns by breaking things up into multiple functions/methods, which you have already done to some extent. Storage however is strictly a matter of types, so we need a type capable of holding the results. I'll use this opportunity to omit the word Manager from the type's name, because all it does is to provide useless abstraction. This type does not manage the config. It is the config, in that it contains all of the config.
type Config struct {
ClientMapConfigs []ClientMapConfig
DataMapConfigs []DataMapConfig
ProcessDataConfigs []ProcessDataConfig
}
Notice the fields start with an upper-case letter, making them public. This communicates that there could be nonsense in there, as nothing is protected from writes, which aligns with the fact that we read this data from files. A correct program must validate this data before using it. You could then communicate the validity of the validated data in the variable name.
func main() {
validConfig := getValidConfig("path/to/dir")
// ...
}
func getValidConfig(configDirectoryPath string) *Config {
config, err := NewConfigFromConfigDirectory(configDirectoryPath)
if err != nil {
log.Printf("Failed to read config from dir '%s': %v\n", configDirectoryPath, err)
os.Exit(1)
}
if err = ValidateConfig(config); err != nil {
log.Printf("Config from dir '%s' failed to validate: %v\n", configDirectoryPath, err)
os.Exit(1)
}
}
func NewConfigFromConfigDirectory(configDirectoryPath string) *Config {
// <- read individual configs and add to slices here
return &Config{ // This is the closest to a "constructor" that Go has.
ClientMapConfigs: clientMapConfigs,
DataMapConfigs: dataMapConfigs,
ProcessDataConfigs: processDataConfigs,
}
}
Notice that there is no imminent need for the functions validating and reading the config to have a receiver, i.e. be a method of a struct. They're fine as standalone functions until your requirements change in ways which demand the introduction of statefulness for either logic.
Also I use exit code 1 for the error-cases here, because Golang uses code 2 when the program terminates due to a panic. The former can be thought of as a problem with the environment, while the later indicates a problem within the program itself. It's a useful distinction to make, and aligns with the semantics of Exception versus RuntimeException which you may know from Java.

I can have let's say 10 different configs (files) and each of those configs can have their own structs since it's a different configs so I need to have separate struct for them
That looks like dynamic JSON struct unmarshalling, which was presented in 2015 by John Asmuth in decoding with mixed structures
You can run the following example here.
type Dog struct {
Name string
Frisbees int
}
type Cat struct {
Name string
Strings int
}
type RawAnimal struct {
Type string
Cat
Dog
}
type Animal RawAnimal
func (a *Animal) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, (*RawAnimal)(a)); err != nil {
return err
}
switch a.Type {
case "cat":
return json.Unmarshal(data, &a.Cat)
case "dog":
return json.Unmarshal(data, &a.Dog)
}
return fmt.Errorf("unknown type %q", a.Type)
}
From there, your ConfigManager will instantiate the right Config structure, depending on the raw JSON read.

I think the trouble is that you're looking at Go from a Java/C# perspective and thus struggling to make sense of the features. If you have the time, then I would suggest that you go thru some Go tutorials or books before you start coding (this one is pretty good: https://www.amazon.com/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440)
To answer your question directly, what you need to do is to create a function which returns a pointer to an object of the struct (see here for a simple example: https://gobyexample.com/structs)
Taking ClientMetric as an example:
func NewClientMetric(ClientID int, CustomerData CustomerData, LegCustomer []int, OtherIds []int, CatID int) (*ClientMetric, error) {
//validate your inputs
//in case of errors, create and error message in the variable err and then: return nil, err
//other code which would go into a typical constructor would go here
return &ClientMetric{ClientID,CustomerData, LegCustomer, OtherIds, CatID}, nil
}
In this case, the function NewClientMetric is the constructor and it returns a pointer/reference to the newly created object. It also returns an error object, which is the same as saying that the constructor throws exceptions. Just as you would need to use try/catch in Java, you would need to check to handle the err variable returned by this function.
You would need to make similar functions for each of your types.
As for getters & setters, generally speaking, that should be avoided in Go. You can access the attributes of a struct directly. A function (like a getter) is only useful if you're going to do something to the attribute before returning it. Something like this:
type Customer struct {
FirstName string
LastName string
}
func (this *Customer) GetFullName() string {
return this.FirstName + " " + this.LastName
}
and these can then be accessed like this:
var customer *Customer
customer = &Customer{"John","Smith")
fmt.Println(customer.FirstName)
fmt.Println(customer.LastName)
fmt.Println(customer.GetFullName())
Please note that attributes, functions and methods which begin with a capital letter are public, the others are private. If FirstName was written as firstName, it would not be accessible outside the package in which it was declared.
Please do note that I'm not checking for errors if the pointer is null/nil, but that is always recommended.

Related

Decode gob output without knowing concrete types

I'm using gob to serialize structs to disk. The struct in question contains an interface field, so the concrete type needs to be registered using gob.Register(...).
The wrinkle here is that the library doing the gob-ing should be ignorant of the concrete type in use. I wanted the serialization to be possible even when callers have defined their own implementations of the interface.
I can successfully encode the data by registering the type on the fly (see trivial example below), but upon trying to re-read that data, gob refuses to accept the un-registered type. Its frustrating, because it feels like all the data is there - why isn't gob just unpacking that as a main.UpperCaseTransformation struct if it's labelled as such?
package main
import (
"encoding/gob"
"fmt"
"os"
"strings"
)
type Transformation interface {
Transform(s string) string
}
type TextTransformation struct {
BaseString string
Transformation Transformation
}
type UpperCaseTransformation struct{}
func (UpperCaseTransformation) Transform(s string) string {
return strings.ToUpper(s)
}
func panicOnError(err error) {
if err != nil {
panic(err)
}
}
// Execute this twice to see the problem (it will tidy up files)
func main() {
file := os.TempDir() + "/so-example"
if _, err := os.Stat(file); os.IsNotExist(err) {
tt := TextTransformation{"Hello, World!", UpperCaseTransformation{}}
// Note: didn't need to refer to concrete type explicitly
gob.Register(tt.Transformation)
f, err := os.Create(file)
panicOnError(err)
defer f.Close()
enc := gob.NewEncoder(f)
err = enc.Encode(tt)
panicOnError(err)
fmt.Println("Run complete, run again for error.")
} else {
f, err := os.Open(file)
panicOnError(err)
defer os.Remove(f.Name())
defer f.Close()
var newTT TextTransformation
dec := gob.NewDecoder(f)
// Errors with: `gob: name not registered for interface: "main.UpperCaseTransformation"'
err = dec.Decode(&newTT)
panicOnError(err)
}
}
My work-around would be to require implementers of the interface to register their type with gob. But I don't like how that reveals my serialization choices to the callers.
Is there any route forward that avoids this?
Philosophical argumentation
The encoding/gob package cannot (or rather should not) make that decision on its own. Since the gob package creates a serialized form independent of / detached from the app, there is no guarantee that values of interface types will exist in the decoder; and even if they do (matched by the concrete type name), there is no guarantee that they represent the same type (or the same implementation of a given type).
By calling gob.Register() (or gob.RegisterName()) you make that intent clear, you give green light to the gob package to use that type. This also ensures that the type does exist, else you would not be able to pass a value of it when registering.
Technical requirement
There's also a technical point of view that dictates this requirement (that you must register prior): you cannot obtain the reflect.Type type descriptor of a type given by its string name. Not just you, the encoding/gob package can't do it either.
So by requiring you to call gob.Register() prior, the gob package will receive a value of the type in question, and therefore it can (and it will) access and store its reflect.Type descriptor internally, and so when a value of this type is detected, it is capable of creating a new value of this type (e.g. using reflect.New()) in order to store the value being decoded into it.
The reason why you can't "lookup" types by name is that they may not end up in your binary (they may get "optimized out") unless you explicitly refer to them. For details see Call all functions with special prefix or suffix in Golang; and Splitting client/server code. When registering your custom types (by passing values of them), you are making an explicit reference to them and thus ensuring that they won't get excluded from the binaries.

Do I need a mutex if I am returning a copy of the variable rather than a pointer?

I'm a little confused about the use of sync.Mutex in Go. I understand the basic concept (calling Lock() will prevent other goroutines from executing the code between it and Unlock()), but I'm not sure if I need it here. I've seen a fair few C++ answers for this but in each example they all seem to be modifying and accessing a variable directly.
This is my code from a package called configuration, which I will use throughout the application to get (surprisingly) configuration and settings information.
package config
import (
"encoding/json"
"fmt"
"os"
"sync"
log "github.com/sirupsen/logrus"
)
/*
ConfigurationError is an implementation of the error interface describing errors that occurred while dealing with this
package.
*/
type ConfigurationError string
/*
Error prints the error message for this ConfigurationError. It also implements the error interface.
*/
func (ce ConfigurationError) Error() string {
return fmt.Sprintf("Configuration error: %s", string(ce))
}
/*
configuration is a data struct that holds all of the required information for setting up the program. It is unexported
to prevent other packages creating more instances. Other packages that need settings information should call Current()
to access a copy of the unexported programConfig package variable.
*/
type configuration struct {
sync.RWMutex
LogLevel log.Level `json:"logLevel,omitempty"` //Logging
LogLocation string `json:"logLocation,omitempty"` //-
HttpPort int `json:"port,omitempty"` //Web
LoginUri string `json:"loginUri"` //-
WebBaseUri string `json:"webBaseUri"` //-
StaticBaseUri string `json:"staticBaseUri"` //-
ApiBaseUri string `json:"apiBaseUri"` //-
StaticContentLocalPath string `json:"staticContentLocalPath"` //-
MaxSimultaneousReports int `json:"maxSimultaneousReports"` //Reporting
}
var programConfig configuration
/*
Current returns a copy of the currently loaded program configuration.
*/
func Current() configuration {
programConfig.RLock()
defer programConfig.RUnlock()
return programConfig
}
/*
Load attempts to load a JSON settings file containing a representation of the Configuration struct. It will then set
the value of the package-level config struct to the loaded values. Some settings changes will require a restart of the
server application.
filepath - the full path of the settings file including a leading slash or drive name (depending on the OS).
*/
func Load(filepath string) error {
//Open the file for reading.
settingsFile, err := os.Open(filepath)
if err != nil {
return ConfigurationError(err.Error())
}
defer settingsFile.Close()
//Decode JSON into package level var.
decoder := json.NewDecoder(settingsFile)
newSettings := configuration{}
err = decoder.Decode(&newSettings)
if err != nil {
return ConfigurationError(err.Error())
}
programConfig.Lock() //I'm not 100% sure this is the correct use of a mutex for this situation, so check up on that.
programConfig = newSettings
programConfig.Unlock()
return nil
}
As you can see, I've used mutex in two places.
In Current(). Do I need this here if the function is not returning a pointer but a copy of the programConfig variable? The only way the underlying package variable will be modified is through the Load() function.
In the Load() function. This can be called at any time by any goroutine, although it rarely will be.
Given that, am I using them correctly and why do I need one when reading a copy of the data (if so)?
When you read data which can be written at the same time you need a mutex. Otherwise it might happen that you read while it's written and get half of the old data and half of the new data.
So your example seems to be just fine. Because you are probably reading the config very often but writing it rarely your usage of a RWLock makes sense. This means that multiple threads can read at the same time as long as it's not written.
What in your code looks dangerous is:
programConfig.Lock()
programConfig = newSettings
programConfig.Unlock()
Because programConfig contains the Mutex you are doing the Lock and Unlock on different instances which will lead to deadlocks. You should add the Mutex to the "parent" of the instance. In this case probably the package.

Using empty interfaces in go

I am trying to understand the code that is used at my company. I am new to go lang, and I have already gone through the tutorial on their official website. However, I am having a hard time wrapping my head around empty interfaces, i.e. interface{}. From various sources online, I figured out that the empty interface can hold any type. But, I am having a hard time figuring out the codebase, especially some of the functions. I will not be posting the entire thing here, but just the minimal functions in which it has been used. Please bear with me!
Function (I am trying to understand):
func (this *RequestHandler) CreateAppHandler(rw http.ResponseWriter, r *http.Request) *foo.ResponseError {
var data *views.Data = &views.Data{Attributes: &domain.Application{}}
var request *views.Request = &views.Request{Data: data}
if err := json.NewDecoder(r.Body).Decode(request); err != nil {
logrus.Error(err)
return foo.NewResponsePropogateError(foo.STATUS_400, err)
}
requestApp := request.Data.Attributes.(*domain.Application)
requestApp.CreatedBy = user
Setting some context, RequestHandler is a struct defined in the same package as this code. domain and views are seperate packages. Application is a struct in the package domain. The following two structs are part of the package views:
type Data struct {
Id string `json:"id"`
Type string `json:"type"`
Attributes interface{} `json:"attributes"`
}
type Request struct {
Data *Data `json:"data"`
}
The following are part of the package json:
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
func (dec *Decoder) Decode(v interface{}) error {
if dec.err != nil {
return dec.err
}
if err := dec.tokenPrepareForDecode(); err != nil {
return err
}
if !dec.tokenValueAllowed() {
return &SyntaxError{msg: "not at beginning of value"}
}
// Read whole value into buffer.
n, err := dec.readValue()
if err != nil {
return err
}
dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
dec.scanp += n
// Don't save err from unmarshal into dec.err:
// the connection is still usable since we read a complete JSON
// object from it before the error happened.
err = dec.d.unmarshal(v)
// fixup token streaming state
dec.tokenValueEnd()
return err
}
type Decoder struct {
r io.Reader
buf []byte
d decodeState
scanp int // start of unread data in buf
scan scanner
err error
tokenState int
tokenStack []int
}
Now, I understood that, in the struct Data in package views, Application is being set as a type for the empty interface. After that, a pointer to Request in the same package is created which points to the variable data.
I have the following doubts:
What exactly does this keyword mean in Go? What is the purpose of writing this * RequestHandler?
Initialization of a structure in Go can be done while assigning it to a variable by specifying the values of all it's members. However, here, for the struct Data, only the empty interface value is assigned and the values for the other two fields are not assigned?
What is the advantage of assigning the Application struct to an empty interface? Does it mean I can use the struct members using the interface variable directly?
Can someone help me figure out the meaning of this statement? json.NewDecoder(r.Body).Decode(request)?
While I know this is too much, but I am having a hard time figuring out the meaning of interfaces in Go. Please help!
this is not a keyword in go; any variable name can be used there. That is called the receiver. A function declared in that way must be called like thing.func(params), where "thing" is an expression of the type of the receiver. Within the function, the receiver is set to the value of thing.
A struct literal does not have to contain values for all the fields (or any of them). Any fields not explicitly set will have the zero value for their types.
As you said, an empty interface can take on a value of any type. To use a value of type interface{}, you would use type assertion or a type switch to determine the type of the value, or you could use reflection to use the value without having to have code for the specific type.
What specifically about that statement do you not understand? json is the name of a package in which the function NewDecoder is declared. That function is called, and then the Decode function (which is implemented by the type of the return value of NewDecoder) is called on that return value.
You may want to take a look at Effective Go and/or The Go Programming Language Specification for more information.

Instantiating a struct via name using a string in go

I am trying to create a function that takes a []byte and an interface{} (standing for the struct) and returns an interface{} as the struct type passed into the func.
Something like this:
package main
import (
"encoding/json"
)
func UnmarshalFromJSONArray(sms []byte,tt string) (interface{}) {
var ts = new(tt)
err := json.Unmarshal(sms,&ts)
if(err != nil) {
fmt.Println(err)
}
return sms
}
So that method would run something like this:
// let's say a struct has the following definition:
type MyStructType struct {
Id int
Name string
Desc string
}
// we can some how get its fully qualified class name (this may require reflection?) or pass it into the UnMarshal method direction some how.
mst := "package.MyStructType",
// and then assume a byte array ba that has JSON format for
ba := []byte(`{"Id":"3","Name":"Jack","Desc":"the man"}`)
stct := UnmarshalFromJSONArray(ba,mst)
MyStructureType out := stct
// leaving "stct" being the unmarshalled byte array which can be used like any other struct of type "MyStructureType"
The key being that I never need to know what the fields of MyStructureType are before unmarshalling. All I need are the name of the struct and some way to instance one and then populate it with JSON byte array data that matches its fields. Hopefully that is possible (it is trivial in java using reflection). So I want to basically unmarshal an anonymous struct type by it's name without needing to know what fields it has.
Any suggestions?
The short answer is that this is impossible. There is no string to type translator in Go. You can make a map of strings to reflect.Type's, but you would need to know the possible options ahead of time or you need to provide the caller with a way to register types (perhaps in init).
Assuming you have found a way to resolve the string to its reflect.Type, you can simply call reflect.New(typ).Interface() to get the pointer you need to pass to json.Unmarshal().
The best answer is to avoid trying this all together. Writing idiomatic Java in Go isn't really possible. If I knew more about your problem, I could give you a more idiomatic Go solution.

Constants in Go established during init

In my Go program, there are configuration values that I want to be constant for the duration of program execution, but that I want to be able to change at the deployment site. As far as I can tell, there's no way to achieve this with the const keyword, since (again, as far as I can tell) its value must be a constant specified at compile time. This means that the only way to achieve what I want would be to declare normal variables and initialize them during the package's init function. It's not that that won't work, but rather that there will now be nothing to prevent these pseudo-constant's values from changing.
My two questions are:
Am I missing something about how const works?
Assuming I'm not, what's the preferred way to handle this? A public function that returns a private variable that I never expose, never changing it? Just hoping people don't alter the variables, since they're really configuration settings?
Create a file "config.go" and create the vars you want to expose.
Don't export them (make them all lower case). Instead create public (upper case) funcs that give access to each item.
package config
var x = 10
func X() int {
return x
}
When you want those variables you simply import ./config and use them in code as follows:
if config.X()
Obviously, you can set the variables in the package init.
The following code is almost the same as the second method of #Christopher, except that it is not a module, it located in the main package.
package main
import (
"os"
)
type Config struct {
debug bool
key string
proxyNumber int
}
func (c *Config) Debug() bool {
return c.debug
}
func (c *Config) Key() string {
return c.key
}
func (c *Config) ProxyNumber() int {
return c.proxyNumber
}
const (
CONFIG_NAME = "config.ini"
)
var config *Config
func init() {
DefaultConfig()
if Exists(CONFIG_NAME) {
//try to save the config file
}else {
//try to load from the config file
}
}
func DefaultConfig() {
config = &Config{debug:true, key:"abcde",
proxyNumber:5,
}
}
//Exist: check the file exist
func Exists(path string) bool {
_, err := os.Stat(path)
if err == nil { return true }
if os.IsNotExist(err) { return false }
return false
}
you can use config to load and save the config file.
This is a very good question because it delves into what I suspect may be an omission from Go - immutable state.
From the language reference, "constant expressions may contain only constant operands and are evaluated at compile-time."
You cannot make vars constant, which is a shame. Joe's answer proposes encapsulation as a solution, which will work well - but it's verbose, tedious and might introduce errors.
By comparison, many impure functional languages combine mutable variables with single-assignment immutable values. For example, Scala has the keywords 'val' and 'var'; the meaning of Scala's 'var' is quite similar to Go's 'var'. Immutability is a useful tool in the toolbox because referentially-transparent side-effect-free functions can be written, alongside stateful mutable procedural code. Both have their place. Immutability is also an valuable tool for concurrency because there is no worry about possible race conditions if immutable values are shared between goroutines.
So in my opinion, amongst its many strengths, this is one of Go's shortcomings. It would presumably not be hard to support vals as well as vars, the difference being that the compiler checks that each val is assigned exactly once.
Until that feature is added, you have encapsulation as your only option.
You can do something like this:
package main
import (
"fmt"
"strconv"
)
var a string
func main() {
myvar, err := strconv.Atoi(a)
if err != nil {
fmt.Println(err)
}
fmt.Println(myvar)
}
and compile the program with
go build -ldflags '-X main.a 10' test.go
That way you can define a constant during compile time.
Just use standard go flags with iniflags. Standard go flags allow setting arbitrary config variables at program start via passing command-line flags, while iniflags "magically" add support for reading config variables from ini files.
You can wrap the variable in a function that returns its value:
func genConst(x int) func() int {
return func() int {
return x
}
}
var Constx = genConst(5)
var x1 = Constx()
This way the value cannot be changed by accident, even in the file where it's defined

Resources