Generic attribution to field X, present across multiples types - go

Currently, I'm working with a set of structures, which define multiple versions of a document. Most of the fields are shared across these different versions, and the actual differences are pretty subtle. What I'm trying to do is refactor the code that parses this document. For that, it would be really good if I could generalize some attributions, where I don't need to know exactly what type I'm working to know that the type will have a specific field.
I've thought about using reflection but if I can avoid it I would.
Lets say we have:
type v1 struct{
a int
}
and
type v2 struct{
a int
b string
}
what I would like to do is something like
func main(){
var v1 v1
var v2 v2
foo(v1)
foo(v2)
}
func foo (root interface{}){
root.a = x
}
is it possible? or is there any other way?
edit:
1 - this is not a duplicate of "Get all fields from an interface" as my problem is not to figure out what type I'm dealing with, but to manipulate/treat different types the same way.
2 - this could be a duplicate of "how to write a function to process two types of input data in golang" but the answer provided fails to solve my issue.

Use anonymous fields, methods and interfaces. You can define a new struct that contains all the common properties to all other structs. Then, an interface could be defined over this shared struct, that lists all the methods to handle the common properties. Finally, in the previous structs you only need to replace all the common fields with this new interface. At this point, you are able to write generic functions that take the interface as input and handle internal common fields through exposed methods.
type SettableA interface{
SetA(int)
A() int
}
type sharedA struct {
a int
}
func (s *sharedA) SetA(val int) {
s.a = val
}
func (s *sharedA) A() int {
return s.a
}
type v1 struct {
SettableA
}
type v2 struct {
SettableA
b string
}
func foo(root SettableA) {
root.SetA(5)
}
func main() {
v1var := v1{
SettableA: &sharedA{},
}
foo(v1var)
v2var := v2{
SettableA: &sharedA{},
b: "test",
}
foo(v2var)
fmt.Printf("V1: %v\nV2: %v\n", v1var.A(), v2var.A())
}
Here the interface is not strictly necessary, but it allows you to write a generic function that handles different concrete types.
https://play.golang.org/p/BgxYrbGE426

Related

Recursive type conversion between two Go structs with parallel structure

Short Question:
Is it possible to do type conversion in Go between two different structs, if both of those structs contain fields that are also struct (different types, but compatible)? See Example 2 below for what I'd like to achieve.
I suspect this is not possible since the types of A and B are not identical any more, but am wondering if this could somehow be achieved with type conversion?
Background:
I'm working on a REST API (let's call it X) that is mostly a tiny wrapper around another REST API (Y). One of the endpoints I'm building in X, I'm mostly just exposing the response from Y, but I do need to rename the JSON field names. If the response from Y is one-level (i.e. without nested structs) I can do the renaming by type conversion as shown in Example 1. However, if the response from Y contains nested structs, the type conversion does not seem to work any more, assuming we want to rename fields on both levels (i.e. on the parent and the child). See Example 2.
For example, I'd like to map the JSON from Y:
{
"Num": 1,
"Child": {
"Num": 2
}
}
to a response in X:
{
"NumB": 1,
"Child": {
"NumB": 2
}
}
I know there are also other ways on how the JSON field names could be renamed, but I'm just wondering it something like this could be achieved with type conversion.
Example 1 (conversion passes without issues):
package main
import "fmt"
func main() {
type A struct {
Num int
}
type B struct {
Num int `json:"NumB"`
}
a := A{1}
b := B(a) // works
fmt.Println(b)
}
Example 2 (does not compile):
package main
import "fmt"
func main() {
type AC struct {
Num int
}
type A struct {
Num int
Child AC
}
type BC struct {
Num int `json:"NumB"`
}
type B struct {
Num int `json:"NumB"`
Child BC `json:"Child"`
}
a := A{1, AC{2}}
b := B(a) // does not work
fmt.Println(b)
}
I get the following error:
./main.go:25:8: cannot convert a (type A) to type B
According to #JimB comment: such conversions are not supported by the language (as least not in Go 1.15).
Some of the alternatives for mapping such structs:
manually copying fields from one struct to the other
https://github.com/jinzhu/copier (as #mh-cbon suggested)
https://github.com/mitchellh/mapstructure

How to use runtime.Object to create CRD generic functions in go [duplicate]

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

Immutable Struct in Golang

Is it possible to define an immutable struct in Golang? Once initialized then only read operation on struct's field, no modification of field values. If so, how to do that.
It is possible to make a struct read-only outside of its package by making its members non-exported and providing readers. For example:
package mypackage
type myReadOnly struct {
value int
}
func (s myReadOnly) Value() int {
return s.value
}
func NewMyReadonly(value int) myReadOnly{
return myReadOnly{value: value}
}
And usage:
myReadonly := mypackage.NewMyReadonly(3)
fmt.Println(myReadonly.Value()) // Prints 3
There is no way to mark fields/variables as read only in a generic way. The only thing you could do is marking fields/variable as unexported (first letter small) and provide public getters to prevent other packages editing variables.
There is no way to define immutable structures in Go: struct fields are mutable and the const keyword doesn't apply to them. Go makes it easy however to copy an entire struct with a simple assignment, so we may think that passing arguments by value is all that is needed to have immutability at the cost of copying.
However, and unsurprisingly, this does not copy values referenced by pointers. And the since built-in collections (map, slice and array) are references and are mutable, copying a struct that contains one of these just copies the pointer to the same underlying memory.
Example :
type S struct {
A string
B []string
}
func main() {
x := S{"x-A", []string{"x-B"}}
y := x // copy the struct
y.A = "y-A"
y.B[0] = "y-B"
fmt.Println(x, y)
// Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified!
}
Note : So you have to be extremely careful about this, and not assume immutability if you pass a parameter by value.
There are some deepcopy libraries that attempt to solve this using (slow) reflection, but they fall short since private fields can't be accessed with reflection. So defensive copying to avoid race conditions will be difficult, requiring lots of boilerplate code. Go doesn't even have a Clone interface that would standardize this.
Credit : https://bluxte.net/
if you write a functional struct by golang, it must be an immutable struct, eg
you can write maybe struct definite
type Maybe[T any] struct {
v T
valid bool
}
func (m Maybe[T]) Just() T {
return m.v
}
func (m Maybe[T]) Nothing() bool {
return m.valid == false
}
func Just[T any](v T) Maybe[T] {
return Maybe[T]{
v: v,
valid: true,
}
}
func Nothing[T any]() Maybe[T] {
return Maybe[T]{
valid: false,
}
}
the maybe struct is a immutable struct

Circular import with structs [duplicate]

This question already has answers here:
Registering packages in Go without cyclic dependency
(2 answers)
Closed 7 years ago.
I have a project with several modules in Go. I am having problem with circular imports because of the scenario below:
Details
A module Game contains a struct with the current Game state. Another module (Modifier) is doing some game specific stuff and calculations and therefore modifies the game state. Because of this, Modifier will need the struct Game, but not any methods from Game. Modifier is called from Game and here we have the circular import.
Problem:
Game initiates Modifier
Modifier needs Game struct
It seems to me that this is a common scenario, so I wonder how I should solve it in the best way. My solution would be to create a third module "Structs" which just contains all the structs for the whole application. Is this a good solution?
With the 3rd package option:
yourgame/
state/
state.go
modifier/
modifier.go
main.go
main.go would glue the two components together:
import "yourgame/state"
import "yourgame/modifier"
type Game struct {
state state.State
modifier modifier.Modifier
}
func main() {
// something like:
var game Game
game.modifier.Modify(game.state)
}
This approach is probably too tightly coupled though. Rather than manipulating an essentially global state object, I would try to slice up the data into just what you need for the modifier.
Reasoning in the abstract is hard, so here's a concrete example of what I mean. In your game:
type Object struct {
ID, X, Y int
// more data here
}
type Game struct {
Objects map[int]*Object
}
In your "modifier", let's suppose we had an AI module that moves an object. If all he cares about is the position of a single object you can create an interface:
// in yourgame/modifier
type Object interface {
GetCoordinates() (int, int)
SetCoordinates(int, int)
}
type Modifier struct {}
func (m *Modifier) Update(obj Object) { }
Then we just have to add those methods to our original Object:
type (obj *Object) GetCoordinates() (int, int) {
return obj.X, obj.Y
}
type (obj *Object) SetCoordinates(x, y int) {
obj.X, obj.Y = x, y
}
And now you can pass objects to your modifier without needing a cyclic dependency.
Now if it turns out your "modifier" interface ends up looking almost exactly the same as your game object, then a 3rd package of structs is probably reasonable so you aren't always repeating yourself. For an example consider net/url.
Normally if package B has code that directly reads/modifies A.Type then that code should be in package A.
At least the parts of it if that need direct access should.
To split something between separate packages A and B you'd normal try to isolate an API for access to A.Type that can be expressed as an interface. Then B would define and use this interface and A.Type would implement it (implicitly, without needing to include B's definition of it).
Then something (possibly A, possibily a separate package) would use B by passing an A.Type or *A.Type value as appropriate.
Or depending on your design the relationship could be reversed, with B.OtherType implicitly implementing an interface defined and used by A.
Or both A and B could use each other only through interfaces; it all depends on the details.
E.g. perhaps something like:
package Game // "A"
type State struct {
data int // etc
}
func (s State) IsValid() bool { return true }
func (s *State) ChangeY(arg int) error { return nil }
// …etc…
and:
package Modifier // "B"
type GameState interface {
IsValid() bool
ChangeY(int) error
}
type M struct {
s GameState
//…
}
func New(s GameState) *M {
return &M{s: s}
}
func (m M) DoSomething() {
if s.IsValid() {
// …
}
s.ChangeY(42)
// …etc…
}
I'd define type(Game in this case) and all its methods in same one package. You can't even define methods on type imported from another package according to language spec,
//you should first do
type MyPackageType ImportedType
//and only then
func (foo MyPackageType) Modify() {
...
}

slice of struct != slice of interface it implements?

I have an interface Model, which is implemented by struct Person.
To get a model instance, I have the following helper functions:
func newModel(c string) Model {
switch c {
case "person":
return newPerson()
}
return nil
}
func newPerson() *Person {
return &Person{}
}
The above approach allows me to return a properly typed Person instance (can easily add new models later with same approach).
When I attempted to do something similar for returning a slice of models, I get an error. Code:
func newModels(c string) []Model {
switch c {
case "person":
return newPersons()
}
return nil
}
func newPersons() *[]Person {
var models []Person
return &models
}
Go complains with: cannot use newPersons() (type []Person) as type []Model in return argument
My goal is to return a slice of whatever model type is requested (whether []Person, []FutureModel, []Terminator2000, w/e). What am I missing, and how can I properly implement such a solution?
This is very similar to a question I just answered: https://stackoverflow.com/a/12990540/727643
The short answer is that you are correct. A slice of structs is not equal to a slice of an interface the struct implements.
A []Person and a []Model have different memory layouts. This is because the types they are slices of have different memory layouts. A Model is an interface value which means that in memory it is two words in size. One word for the type information, the other for the data. A Person is a struct whose size depends on the fields it contains. In order to convert from a []Person to a []Model, you will need to loop over the array and do a type conversion for each element.
Since this conversion is an O(n) operation and would result in a new slice being created, Go refuses to do it implicitly. You can do it explicitly with the following code.
models := make([]Model, len(persons))
for i, v := range persons {
models[i] = Model(v)
}
return models
And as dskinner pointed out, you most likely want a slice of pointers and not a pointer to a slice. A pointer to a slice is not normally needed.
*[]Person // pointer to slice
[]*Person // slice of pointers
Maybe this is an issue with your return type *[]Person, where it should actually be []*Person so to reference that each index of the slice is a reference to a Person, and where a slice [] is in itself a reference to an array.
Check out the following example:
package main
import (
"fmt"
)
type Model interface {
Name() string
}
type Person struct {}
func (p *Person) Name() string {
return "Me"
}
func NewPersons() (models []*Person) {
return models
}
func main() {
var p Model
p = new(Person)
fmt.Println(p.Name())
arr := NewPersons()
arr = append(arr, new(Person))
fmt.Println(arr[0].Name())
}
As Stephen already answered the question and you're a beginner I emphasize on giving advises.
A better way of working with go's interfaces is not to have a constructor returning
the interface as you might be used to from other languages, like java, but to have
a constructor for each object independently, as they implement the interface implicitly.
Instead of
newModel(type string) Model { ... }
you should do
newPerson() *Person { ... }
newPolitician() *Politician { ... }
with Person and Politician both implementing the methods of Model.
You can still use Person or Politician everywhere where a Model
is accepted, but you can also implement other interfaces.
With your method you would be limited to Model until you do a manual conversion to
another interface type.
Suppose I have a Person which implements the method Walk() and a Model implements ShowOff(), the following would not work straight forward:
newModel("person").ShowOff()
newModel("person").Walk() // Does not compile, Model has no method Walk
However this would:
newPerson().ShowOff()
newPerson().Walk()
As others have already answered, []T is a distinct type. I'd just like to add that a simple utility can be used to convert them generically.
import "reflect"
// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// There is no need to check, we want to panic if it's not slice or array
intf := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
intf[i] = v.Index(i).Interface()
}
return intf
}
Now, you can use it like this:
ToIntf([]int{1,2,3})
Types T and []T are distinct types and distinct are their methods as well, even when satisfying the same interface. IOW, every type satisfying Model must implement all of the Model's methods by itself - the method receiver can be only one specific type.
Even if Go's implementation allowed this, it's unfortunately unsound: You can't assign a []Person to a variable of type []Model because a []Model has different capabilities. For example, suppose we also have Animal which implements Model:
var people []Person = ...
var models []Model = people // not allowed in real Go
models[0] = Animal{..} // ???
var person Person = people[0] // !!!
If we allow line 2, then line 3 should also work because models can perfectly well store an Animal. And line 4 should still work because people stores Persons. But then we end up with a variable of type Person holding an Animal!
Java actually allows the equivalent of line 2, and it's widely considered a mistake. (The error is caught at run time; line 3 would throw an ArrayStoreException.)

Resources