Unmarshal YAML into unknown struct - go

Sorry for the confusing title, I'm having trouble wording this question. So lets say I have a YAML config file like this
animals:
-
type: whale
options:
color: blue
name: Mr. Whale
features:
-
type: musician
options:
instruments:
- Guitar
- Violin
Very contrived example, but it's directly analogous to what I'm really working with.
So now I have some structs to marshal this config into
type Config struct {
AnimalConfigs []*AnimalConfig `yaml:"animals"`
}
type AnimalConfig struct{
Type string
Options map[string]string // ????
Features []*FeatureConfig
}
type FeatureConfig struct{
Type string
Options ????
}
So the problem here is that the animal types (whale, etc..), and features (musician, etc...) are not determined ahead of time, they can be added on as separate modules and can each have their own configurations. So say someone is using this library and wants to add their own animal. I do not know what this animal is, what it's options will be, and what it's features will be. I also don't know the structure of the feature's. All I know is that it will have a type property, and an options property. I would like the developer to be able to add custom animals and features, and my library can just do something like YourAnimal.Create(yourConfig).
I'm using the go-yaml library. As you can see in the AnimalConfig struct, my initial idea was to have the options and features just be map[string]string, and then let the custom module unmarshal that string into their own struct, but that wouldn't work for example with the musician feature because instruments is a list, not a string. Thanks!

I think in general what you are asking is how to unmarshal YAML when you don't know the structure which will be produced, yes? If so, what I've done is use ghodss/yaml to convert YAML to JSON, then use the standard encoding/json to unmarshal. This gets you a struct with everything in the YAML doc, but you have to "type switch" your way through it, and key names, of course, may not be known a prioir.
Here's an example: https://play.golang.org/p/8mcuot-lw0y

You could make your config of type map[string]interface{} and let the developer using your library decode interface{} into required struct.
Example: https://play.golang.org/p/RVqKP09KR8

Related

How to unmarshal protbuf data into custom struct in Golang

I have a proxy service that translate protobuf into another struct. I
can just write some manual code to do that, but that is inefficient and boilerplate. I can also transform the protobuf data to JSON, and deserlize the JSON data into the destination struct, but the speed is slow and it is CPU heavy.
The Unmarshaler interface is now deprecated, and Message interface have internal types which I cannot implement in my project.
Is there a way I can do this now?
Psuedo code: basically, if Go's reflection supports setting and getting of struct / class fields by some sort of field identifier, then you can do this. Something like this in C# works, so long as the field types in the two classes are the same (because in C#, I'm doing object = object, which ends up being OK if they're the same actual type).
SourceStructType sourceStruct;
DestStructType destStruct;
foreach (Field sourceField in sourceStruct.GetType().GetFields())
{
Field destField = destStruct.GetType().FindFieldByName(sourceField.name);
destStruct.SetFieldValue(destField) = sourceStruct.GetFieldValue(sourceField);
}
If the structs are more complex - i.e. they have structs within them, then you'll have to recurse down into them. It can get fiddly, but once written you'll never have to write it ever again!

Using multiple interfaces in Golang

I'm learning Golang and as an exercise in using interfaces I'm building a toy program. I'm having some problem trying to use a type that "should implement" two interfaces - one way to solve that in C++ and Java would be to use inheritance(there are other techniques, but I think that is the most common). As I lack that mechanism in Golang, I'm not sure how to proceed about it. Below is the code:
var (
faces = []string{"Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"}
suits = []string{"Hearts", "Diamonds", "Spades", "Clubs"}
)
type Card interface {
GetFace() string
GetSuit() string
}
type card struct {
cardNum int
face string
suit string
}
func NewCard(num int) Card {
newCard := card{
cardNum: num,
face: faces[num%len(faces)],
suit: suits[num/len(faces)],
}
return &newCard
}
func (c *card) GetFace() string {
return c.face
}
func (c *card) GetSuit() string {
return c.suit
}
func (c *card) String() string {
return fmt.Sprintf("%s%s ", c.GetFace(), c.GetSuit())
}
What I'm trying to achieve:
I would like to hide my struct type and only export the interface so that the clients of the code use only the "Card" interface
I would like to have a string representation of the struct, hence the implementation of the interface with the "String()" method in order to be able to call "fmt.Println()" on instantiations of my struct
The problem comes when I'm trying to use a new card though the "Card" interface and also trying to get the string representation. I cannot pass the interface as the parameter of the implementation of the "String()" method as there is a compiler error which is related to the addressability of an interface at the core language level(still digging through that documentation). The very simple example of testing exposes the issue:
func TestString(t *testing.T) {
card := NewCard(0)
assert.EqualValues(t, "AceHearts ", card.String(), " newly created card's string repr should be 'AceHearts '")
}
The compiler tells me, for good reason, that "card.String undefined (type card has no field or method string)". I could just add the "String()" method to my "Card" interface, but I do not find that to be clean: I have other entities implemented with the same model and I would have to add that redundancy everywhere; there is already an interface with that method.
What would be a good solution for the above issue that I'm having?
Edit:(to address some of the very good comments)
I do not expect to have another implementation of the Card interface; I'm not sure I grasp why would I want to do that, that is change the interface
I would like to have the Card interface to hide away implementation details and for the clients to program against the interface and not against the concrete type
I would like to always have access to the String() interface for all clients of the "card struct" instantiations(including the ones instantiated via the Card interface). I'm not interested in having clients only with the String interface. In some other languages this can be achieved by implementing both interfaces - multiple inheritance. I'm not saying that is good or wrong, or trying to start a debate about that, I'm just stating a fact!
My intent is to find out if the language has any mechanism to fulfill those requirements simultaneously. If that is not possible or maybe from the point of view of the design the problem should be tackled in a different manner, then I'm ready to be educated
Type assertions are very verbose and explicit and would expose implementation details - they have their places but I do not think they are appropriate in the situation I have
I should go over some prefacing points first:
Interfaces in Go are not the same as interfaces in other languages. You shouldn't assume that every idea from other languages should transfer over automatically. A lot of them don't.
Go has neither classes nor objects.
Go is not Java and Go is not C++. It's type system is significantly and meaningfully different than those languages.
From your question:
I would like to have the Card interface to hide away implementation details and for the clients to program against the interface and not against the concrete type
This is the root of your other problems.
As mentioned in the comments, I see this in multiple other packages and regard it as a particularly pesky anti-pattern. First, I will explain the reasons why this pattern is "anti" in nature.
Firstly and most pertinently, this point is proven by your very example. You employed this pattern, and it has resulted in bad effects. As pointed out by mkopriva, it has created a contradiction which you must resolve.
this usage of interfaces is contrary to their intended use, and you are not achieving any benefit by doing this.
Interfaces are Go's mechanism of polymorphism. The usage of interfaces in parameters makes your code more versatile. Think of the ubiquitous io.Reader and io.Writer. They are fantastic examples of interfaces. They are the reason why you can patch two seemingly unrelated libraries together, and have them just work. For example, you can log to stderr, or log to a disk file, or log to an http response. Each of these work exactly the same way, because log.New takes an io.Writer parameter, and a disk file, stderr, and http response writer all implement io.Writer. To use interfaces simply to "hide implementation details" (I explain later why this point fails), does not add any flexibility to your code. If anything, it is an abuse of interfaces by leveraging them for a task they weren't meant to fulfill.
Point / Counterpoint
"Hiding my implementation provides better encapsulation and safety by making sure all the details are hidden."
You are not achieving any greater encapsulation or safety. By making the struct fields unexported (lowercase), you have already prevented any clients of the package from messing with the internals of your struct. Clients of the package can only access the fields or methods that you have exported. There's nothing wrong with exporting a struct and hiding every field.
"Struct values are dirty and raw and I don't feel good about passing them around."
Then don't pass structs, pass pointers to struct. That's what you're already doing here. There's nothing inherently wrong with passing structs. If your type behaves like a mutable object, then pointer to struct is probably appropriate. If your type behaves more like an immutable data point, then struct is probably appropriate.
"Isn't it confusing if my package exports package.Struct, but clients have to always use *package.Struct? What if they make a mistake? It's not safe to copy my struct value; things will break!"
All you realistically have to do to prevent problems is make sure that your package only returns *package.Struct values. That's what you're already doing here. A vast majority of the time, people will be using the short assignment :=, so they don't have to worry about getting the type correct. If they do set the type manually, and the choose package.Struct by accident, then they will get a compilation error when trying to assign a *package.Struct to it.
"It helps to decouple the client code from the package code"
Maybe. But unless you have a realistic expectation that you have multiple existent implementations of this type, then this is a form of premature optimization (and yes it does have consequences). Even if you do have multiple implementations of your interface, that's still not a good reason why you should actually return values of that interface. A majority of the time it is still more appropriate to just return the concrete type. To see what I mean, take a look at the image package from the standard library.
When is it actually useful?
The main realistic case where making a premature interface AND returning it might help clients, is this:
Your package introduces a second implementation of the interface
AND clients have statically and explicitly (not :=) used this data type in their functions or types
AND clients want to reuse those types or functions for the new implementation also.
Note that this wouldn't be a breaking API change even if you weren't returning the premature interface, as you're only adding a new type and constructor.
If you decided to only declare this premature interface, and still return concrete types (as done in the image package), then all the client would likely need to do to remedy this is spend a couple minutes using their IDE's refactor tool to replace *package.Struct with package.Interface.
It significantly hinders the usability of package documentation
Go has been blessed with a useful tool called Godoc. Godoc automatically generates documentation for a package from source. When you export a type in your package, Godoc shows you some useful things:
The type, all exported methods of that type, and all functions that return that type are organized together in the doc index.
The type and each of its methods has a dedicated section in the page where the signature is shown, along with a comment explaining it's usage.
Once you bubble-wrap your struct into an interface, your Godoc representation is hurt. The methods of your type are no longer shown in the package index, so the package index is no longer an accurate overview of the package as it is missing a lot of key information. Also, each of the methods no longer has its own dedicated space on the page, making it's documentation harder to both find and read. Finally it also means that you no longer have the ability to click the method name on the doc page to view the source code. It's also no coincidence that in many packages that employ this pattern, these de-emphasized methods are most often left without a doc comment, even when the rest of the package is well documented.
In the wild
https://pkg.go.dev/github.com/zserge/lorca
https://pkg.go.dev/github.com/googollee/go-socket.io
In both cases we see a misleading package overview, along with a majority of interface methods being undocumented.
(Please note I have nothing against any of these developers; obviously every package has it's faults and these examples are cherry picked. I'm also not saying that they had no justification to use this pattern, just that their package doc is hindered by it)
Examples from the standard library
If you are curious about how interfaces are "intended to be used", I would suggest looking through the docs for the standard library and taking note of where interfaces are declared, taken as parameters, and returned.
https://golang.org/pkg/net/http/
https://golang.org/pkg/io/
https://golang.org/pkg/crypto/
https://golang.org/pkg/image/
Here is the only standard library example I know of that is comparable to the "interface hiding" pattern. In this case, reflect is a very complex package and there are several implementations of reflect.Type internally. Also note that in this case, even though it is necessary, no one should be happy about it because the only real effect for clients is messier documentation.
https://golang.org/pkg/reflect/#Type
tl;dr
This pattern will hurt your documentation, while accomplishing nothing in the process, except you might make it slightly quicker in very specific cases for clients to use parallel implementations of this type that you may or may not introduce in the future.
These interface design principles are meant for the benefit of the client, right? Put yourself in the shoes of the client and ask: what have I really gained?
Not entirely sure if this is what you are looking for but you could try embedding the other interface in Card interface as shown below.
type Printer interface {
String() string
}
type Card interface {
Printer // embed printer interface
GetFace() string
GetSuit() string
}
Interface Card hasn't method String, it doesn't matter, that underlying type card have it, because method is hidden from you (unless you access it via reflection).
Adding String() string method to Card will solve problem:
type Card interface {
GetFace() string
GetSuit() string
String() string
}
The go language does not have subtype polymorsphism. Therefore, the pattern you want to achieve is not encouraged by the very foundations of the language. You may achieve this undesirable pattern by composing structs and interfaces, though.

Handling configurations without defining explicit type objects

I am following the solution (accepted answer) given here as to load configuration values in Go.
So far so good.
However, I want to use standard configuration load functions across different modules of the application and for simplicity and ease of it I am trying to achieve loading configurations without explicitly defining a customer object such as type Configuration struct.
Because each configuration file would be different and I don't want to define multiple structs and structs everywhere and then change them when a new value is added/deleted in the configurations.
I might be unfair to compare but I am looking for which in python would be just like this:
//in config.py
ENVIRONMENT = 'PROD'
//in main.py
import config
...
if config.ENVIRONMENT == 'PROD':
...
Is there such a possibility?
You can use a map[string]string type if all your config values are strings or a map[string]interface{} type if you need arbitrary value types.
Although map[string]interface{} is a bit more cumbersome and a bit less safe, because you can cast interface{} to any type.
Here is a guide for using map[string]interface{}: https://bitfieldconsulting.com/golang/map-string-interface

Best practices to use own type in golang. Alians to build type

I wonder when or if it should be use own type in golang. When this will be more friendly to understand my code, or when I shouldn't use own type.
Example:
I want to create map type with MAC, and name host:
in first way the simplest I can do that
var machines map[string]string{
"11:22...": "myHost",
"22:33..": "yourHost",
}
in second way
type MAC string
type HOST string
machines := map[MAC]HOST{
MAC("11:22..") : HOST("myHost"),
MAC("22:33..") : HOST("yourHost"),
}
In above exmaple I can get additional controle on my type MAC, HOST trought write method to validation, compare etc it is better ?
Third way
type MACHINES map[string]string
m := MACHINES{}
m = map[string]string{
"11:22.." : "myHost",
"22:33" : "yourHost",
}
above example for me is worst to understand less intuitive to some else. I think that above example should be also filled about HOST, and MAC because type MACHINE nothing to say developer how this should be implement so I would like
type MACHINES map[MAC]HOST
However, please about comment to better understand about usage own type in golang.
Without commenting on your specific example, there are a few reasons you'd generally want to use a new type:
You need to define methods on the type
You don't want the type to be comparable with literals or variables with the type it's derived from (eg. to reduce user confusion or make sure they don't do something invalid like attempt to compare your special string with some other random string)
You just need a place to put documentation, or to group methods that return a specific type (eg. if you have several Dial methods that return a net.Conn, you might create a type Conn net.Conn and return that instead just for the sake of grouping the functions under the Conn type header in godoc or to provide general documentation for the net.Conn returned by the methods).
Because you want people to be able to check if something of a generic type came from your package or not (eg. even if your Conn is just a normal net.Conn, it gives you the option of type switching and checking if it's a yourpackage.Conn as well)
You want a function to take an argument from a predefined list of things and you don't want the user to be able to make new values that can be passed in (eg. a list of exported constants of an unexported type)
Creating type alias is only useful when you require to add extra methods (such as validation functions) or when you want to document the desired use of some value (for example, the net.IP type).
Type alias could help you to prevent API misunderstanding, but won't if you're using constant values. For example, this code is valid:
type Host string
type Mac string
hosts := map[Mac]Host{"ad:cb..": "localhost"}
For further information about how constants work in Go, you can check the Rob Pike's blog post
One of the most important features of Go is interfaces. In Go by defining the method/s of an Interface you implement the interface, and the only way to implement an interface is by adding a Method to your type. For instance, say you want to implement the Stringer interface from the fmt package.
In your example type MACHINES map[string]string you would add a method called String to your type.
func (m MACHINES) String() string {
s := "MACHINES\n"
for k, v := range m {
s += fmt.Sprintf("%v: %v\n", k, v)
}
return s
}
Any other function that accepts the Stringer interfaces can now also accept your MACHINES type since you implemented the Stringer interface.
For example the fmt.Printf checks if the passed in type implements the Stringer interface
m := MACHINES{"foo":"bar", "baz": "bust"}
fmt.Printf("%s", m)
Will invoke MACHINES String method
Example from the playground
You do want to use your own types in my opinion.
As an example, lists of function arguments that are all "string" or all "int" are confusing and very easy to get wrong.
And a comment on your type names. "MAC" is an acronym for Media Access Control so it should stay as all caps. But "HOST" should be "Host" since it is just a word. I don't recall where it is exactly, but there's a recommended form for Go names which is CamelCase with all-capital abbreviations, like "GetIPv4AddressFromDNS"
I think another reason to use your own types, that hasn't been mentioned here, is if you are not sure exactly what the right type for something is e.g. uint8 / uint16 and you want to easily change it later all in one place.
This will however make conversions necessary whenever you want to use the built-in types' methods. Or you will need to define them on your own type.

Similar to .net attributes in Go

What is similar to .net attributes in go lang.
Or how this could be achieved ?
Perhaps the most similar mechanism is Struct Tags. Not the most elegant, but they can be evaluated at runtime and provide metadata on struct members.
From the reflect package documentation: type StructTag
They are used, for example, in JSON and XML encoding for custom element names.
For example, using the standard json package, say I have a struct with a field I don't want to appear in my JSON, another field I want to appear only if it is not empty, and a third one I want to refer to with a different name than the struct's internal name. Here's how you specify it with tags:
type Foo struct {
Bar string `json:"-"` //will not appear in the JSON serialization at all
Baz string `json:",omitempty"` //will only appear in the json if not empty
Gaz string `json:"fuzz"` //will appear with the name fuzz, not Gaz
}
I'm using it to document and validate parameters in REST API calls, among other uses.
If you keep the 'optionally space-separated key:"value"' syntax, you can use the Get Method of StructTag to access the values of individual keys, as in the example.

Resources