Modifying struct - go

I have a struct such as
type Info struct {
Foo string
FooBar string
Services string
Clown string
}
and lets say I have already populated the first 2 fields
input := &Info{
Foo: "true",
Services: "Massage",
}
Is there a way to "reopen" the struct to add missing elements. Something like this :
input = {
input,
Foobar: "Spaghetti",
Clown: "Carroussel"
}
Instead of
input.Foobar = "Spaghetti"
input.Clown = "Carroussel"
I have multiple fields and just don't really like having many lines input.Fields. I didn't find anything like it. So I was wondering.

No, this is not supported by the language's syntax.
Btw, the solution you want to avoid consists of less lines that the theoretical alternative :) (2 lines vs 4 lines in your example).
One could create a helper function which copies non-zero fields from one instance of a struct to another, so you could create a struct with the additional fields using a composite literal and use that as the source, but this requires using reflection, which is slow, and this solution wouldn't be more readable.
See related: "Merge" fields two structs of same type

Related

Two structs having same receiver function implementations, how to remove the duplications

I have two structs that are having same receiver function implementations:
type A struct {
name string
// other fields
}
type B struct {
name string
// other fields
}
type AA struct {
resource A
}
func (a *AA) Get() string {
// process something with a.resource.name
return a.resource.name
}
type BB struct {
resource B
}
func (b *BB) Get() string {
// process something with b.resource.name
return b.resource.name
}
type I interface {
Get() string
}
both structs AA and BB have Get function, in order to satisfy the interface I, this might be a dumb question, but I dont know how I can simplify them to remove the duplications of two Get functions, tried:
having a generic struct and embedded in A & B - cant do this due
to json serializations in the system I use.
embedded AA in BB and calling AA.Get - wont work since name is inside B instead of A
Combine AA and BB with both fields like resourceA and resourceB - this complicates the Get function, since then it needs to handle
create a non-receiver function and use it for both AA and BB - this can work but since there are quite some fields I need, not just name, so the function will end up with quite many parameters.
I cant stop feeling there should be an easier way, and also trying/googling a way to simplify it, but non of them seems to work, could someone point me some directions or hints?
much appreciated!
[UPDATE]
I'm trying to create a Kubernetes operator, which has some CRDs (Custom Resource Definitions), and since I create a generic controller that just take the CRDs and calling their functions (that's why I have interface), but I found I need to implement functions that are exactly the same, like GetName, GetObject, or some functions that manipulate the data and get back the results, and they're all the same across those CRD structs.
I've decided to just create a function that takes required parameters, and reuse the function across the structs, thanks for all the comments.
If you have other suggestions, please feel free to comment or suggest, thanks!

Polymorphism on structs without methods in Go

I'm working on several web server projects in Go, and there is a common problem that I'm always facing. I know we can achieve something like polymorphism in Go with interfaces and methods, but many times I had a scenario that I needed polymorphism on some data-holder structs that (maybe) just had some common fields, and no methods at all.
For example consider a story writing platform, where each user can write short stories and novels:
type ShortStory struct {
Name string
ID int
Body string
}
type LongStory struct {
Name string
ID int
Chapters []string
}
Now I simply want to have a data layer function, say GetStories(), which fetches all stories written by a user from database.
func GetStories(id int) []SOME_TYPE {
...
}
There are really no methods that I want to have on my ShortStory and LongStory structs. I know I can add a dummy method and let them satisfy some Storier interface, then use that interface as return type. But since there is no method I would want on a data container model, adding a dummy method just for the language to enable a feature, seems like a poor design choice to me.
I can also make the function return []interface{}, but that's against the whole idea of "typed language" I believe.
Another way is to have two separate GetShortStories() and GetLongStories() methods, which return a slice of their own type. But at some point I would finally want to merge those two slices into one and there I would again need a []interface{}. Yes, I can return a JSON like:
{
"short_stories" : [...],
"long_stories" : [...]
}
But I want my json to be like:
[{...}, {...}, {...}]
And I wouldn't change my APIs because of a language's limits!
I'm not a pro in Go, so am I missing something here? Is there a Go-ish approach to this, or is it really bad language design on Golang's side?
If you cannot express what you want to do using the features of a language, you should first try to change the way you structure your program before blaming the language itself. There are concepts that cannot be expressed in Go but can be expressed well in other languages, and there are concepts you cannot express well in other languages but you can in Go. Change the way you solve the problem to effectively use the language.
One way you can address your problem is using a different type of struct:
type Story struct {
Name string
ID int
ShortBody string
Chapters []string
}
If the Chapters is empty, then it is a short story.
Another way:
type Story struct {
Name string
ID int
Content StoryContent
}
type StoryContent interface {
Type() string
}
type ShortStory interface {
StoryContent
Body() string
}
type LongStory interface {
StoryContent
Chapters() []string
}
etc.

Struct type first line: _ struct{} [duplicate]

I am working with go, specifically QT bindings. However, I do not understand the use of leading underscores in the struct below. I am aware of the use of underscores in general but not this specific example.
type CustomLabel struct {
core.QObject
_ func() `constructor:"init"`
_ string `property:"text"`
}
Does it relate to the struct tags?
Those are called blank-fields because the blank identifier is used as the field name.
They cannot be referred to (just like any variable that has the blank identifier as its name) but they take part in the struct's memory layout. Usually and practically they are used as padding, to align subsequent fields to byte-positions (or memory-positions) that match layout of the data coming from (or going to) another system. The gain is that so these struct values (or rather their memory space) can be dumped or read simply and efficiently in one step.
#mkopriva's answer details what the specific use case from the question is for.
A word of warning: these blank fields as "type-annotations" should be used sparingly, as they add unnecessary overhead to all (!) values of such struct. These fields cannot be referred to, but they still require memory. If you add a blank field whose size is 8 bytes (e.g. int64), if you create a million elements, those 8 bytes will count a million times. As such, this is a "flawed" use of blank fields: the intention is to add meta info to the type itself (not to its instances), yet the cost is that all elements will require increased memory.
You might say then to use a type whose size is 0, such as struct{}. It's better, as if used in the right position (e.g. being the first field, for reasoning see Struct has different size if the field order is different and also Why position of `[0]byte` in the struct matters?), they won't change the struct's size. Still, code that use reflection to iterate over the struct's fields will still have to loop over these too, so it makes such code less efficient (typically all marshaling / unmarshaling process). Also, since now we can't use an arbitrary type, we lose the advantage of carrying a type information.
This last statement (about when using struct{} we lose the carried type information) can be circumvented. struct{} is not the only type with 0 size, all arrays with 0 length also have zero size (regardless of the actual element type). So we can retain the type information by using a 0-sized array of the type we'd like to incorporate, such as:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
Now this CustomLabel type looks much better performance-wise as the type in question: its size is still 0. And it is still possible to access the array's element type using Type.Elem() like in this example:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
func main() {
f := reflect.ValueOf(CustomLabel{}).Type().Field(0)
fmt.Println(f.Tag)
fmt.Println(f.Type)
fmt.Println(f.Type.Elem())
}
Output (try it on the Go Playground):
constructor:"init"
[0]func()
func()
For an overview of struct tags, read related question: What are the use(s) for tags in Go?
You can think of it as meta info of the type, it's not accessible through an instance of that type but can be accessed using reflect or go/ast. This gives the interested package/program some directives as to what to do with that type. For example based on those tags it could generate code using go:generate.
Considering that one of the tags says constructor:"init" and the field's type is func() it's highly probable that this is used with go:generate to generate an constructor function or initializer method named init for the type CustomLabel.
Here's an example of using reflect to get the "meta" info (although as I've already mentioned, the specific qt example is probably meant to be handled by go:generate).
type CustomLabel struct {
_ func() `constructor:"init"`
_ string `property:"text"`
}
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Tag)
// constructor:"init"
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Type)
// func()
https://play.golang.org/p/47yWG4U0uit

Is it possible to use only one of the return values when initializing members in Go?

I understand how to use multiple return values in go. I further understand that in most cases one of the returns is an error, so ignoring returned values can be dangerous.
Is there a way to ignore a value in struct initializer like this? The below example does not work as Split returns two values, but I am interested only in the first one. I can of course create a variable but...
someFile := "test/filename.ext"
contrivedStruct := []struct{
parentDir string
}{
{ parentDir: filepath.Split(someFile) },
}
It's not possible to use only one of the return values when initializing members in Go.
Using variables clearly expresses your intent.
Go sometimes feels like it could be more succinct, but the Go authors favoured readability over brevity.
Alternatively, use a wrapper function. There are several 'Must' wrapper functions in the standard library, like: template.Must.
func first(args ...string) string {
return args[0]
}
For your particular example, splitting paths, see filepath.Base or filepath.Dir.
No, there is no way to skip one of the returned values in structure initializer.

How to convert one struct to another in Go when one includes another?

I would like to know if there is easy way to convert from one struct to another in Go when one struct includes the other.
For example
type Type1 struct {
Field1 int
Field2 string
}
type Type2 struct {
Field1 int
}
I know that it can be handled like this
var a Type1{10, "A"}
var b Type2
b.Field1 = a.Field1
but if there are many fields, I will have to write numerous assignments. Is there any other way to handle it without multiple assignments?
In a word, is there anything like b = _.omit(a, 'Field2') in javascript?
Not directly, no. You can freely convert between identical types only.
You can get various levels of solutions to this type of problem:
writing the assignments out yourself (likely the best performance)
using reflection to copy from one to the other based on field names
something quick-and-dirty like marshalling one type to JSON then unmarshalling to the other type (which is basically using reflection under the hood with a plaintext middleman, so it's even less efficient, but can be done with little work on your part)

Resources