I've stumbled upon this repository,
https://github.com/prometheus-community/jiralert/blob/a0f0e80e575e71cbf7db565d3296a3a984282dff/pkg/config/config_test.go#L148
The for loop has multiple brackets:
for _, test := range []struct {
missingField string
errorMessage string
}{
{"Name", "missing name for receiver"},
(...)
} {
fields := removeFromStrSlice(mandatory, test.missingField)
(...)
}
configErrorTestRunner(t, config, test.errorMessage)
}
I haven't been able to find anything about this in the go documentation, what is this construct?
The first bracket pair is part of the struct type definition which has the syntax:
struct{
field1 type1
field2 type2
...
}
The second pair is part of the composite literal value, creating a value for the slice of this struct. It has the syntax of:
[]elementType{value1, value2, ...}
The inner, embedded brackets are part of the composite literals creating the struct values of the slice. The type is omitted (it's known from the slice type), so each {field1Value, fieldValue2...} is a struct value.
The third pair defines the block of the for statement. The for statement iterates over the elements of the slice defined by the mentioned composite literal.
To clean up the code for better readability and understanding. Whatever you gave was equivalent to:
type TestStruct struct {
missingField string
errorMessage string
}
testCase := TestStruct {
{
missingField: "Name",
errorMessage: "missing name for receiver",
}
(...)
}
for _, test := range(testCase) {
fields := removeFromStrSlice(mandatory, test.missingField)
}
configErrorTestRunner(t, config, test.errorMessage) is probably from a parent test func
Related
How would I change the position of the json values?
What Im trying to achieve:
[{"key":"f","value":"f"},{"value":"f","key":"f"}]
Problem:
type Struct struct {
Key string `json:"key"`
Value string `json:"value"`
}
func main() {
test := []Struct{ {Key: "test",Value: "wep"}, {Value: "wep",Key: "test"}}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
Running this code prints [{"key":"test","value":"wep"},{"key":"test","value":"wep"}]
I have also tried doing something like this but it just printed empty values
type Struct struct {
Key string `json:"key"`
Value string `json:"value"`
Value2 string `json:"value"`
Key2 string `json:"key"`
}
But how would I be able to switch the position of the key and value field around?
type StructA struct {
Key string `json:"key"`
Value string `json:"value"`
}
type StructB struct {
Value string `json:"value"`
Key string `json:"key"`
}
func main() {
test := []interface{}{
StructA{Key: "test", Value: "wep"},
StructB{Value: "wep", Key: "test"},
}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
https://play.golang.org/p/72TWDU1BMaL
If you're using json.Marshal provided by official package it's not passible to do that. In stead, you can implement your own MarhalJSON method so that you can decide the position of your struct fields.
To the question "can I make a single struct type serialize its fields in a different order or different occasions ?" :
there isn't a simple way to do this.
Regarding struct fields : the code you write shows the assigning operations in a given order, but once your code is compiled, there is no trace of that order anymore.
If you really need this (side note : I would be curious to know about your use case ?), you could create a custom type, with its own .MarshalJSON() method, which would hold a value indicating "fields should be serialized in this order".
If what you need is to send an array of heterogeneous objects, use separate struct types, and an []interface{} array :
type Obj1 struct{
Key string `json:"name"`
Value string `json:"value"`
}
type Obj2 struct{
Value string `json:"value"`
Key string `json:"name"`
}
func main() {
test := []interface{}{ Obj1{Key: "test",Value: "wep"}, Obj2{Value: "wep",Key: "test"}}
bytes, _ := json.Marshal(test)
fmt.Print(string(bytes))
}
https://play.golang.org/p/TOk28gL0eSK
type Person struct {
ID int `json:"id"`
}
type PersonInfo []Person
type PersonInfo2 []struct {
ID int `json:"id"`
}
Is there have difference between PersonInfo (named slice of named structs) and PersonInfo2 (named slice of unnamed structs)
The main difference is how you have to initialize Person objects outside of the PersonInfo/PersonInfo2 initialization. Since PersonInfo2 is an array of the anonymous struct type we know nothing about this type outside of the PersonInfo2 initialization.
So they can both be initialized like this:
m := PersonInfo{{1}, {2}}
n := PersonInfo2{{1},{2}}
However if we want to append an element of the anonymous struct type we would have to specify the full type:
append(n, struct { ID int `json:"id"` }{3})
If we print these out we can see they appear to be the same:
fmt.Printf("%+v\n%+v", m, n)
Outputs:
[{ID:1} {ID:2}]
[{ID:1} {ID:2}]
However they wont be deeply equal because PersonInfo is an array of type Person and PersonInfo2 is an array of anonymous struct type. So the following:
if !reflect.DeepEqual(m,n) {
print("Not Equal")
}
will print "Not Equal".
Here is a link to see for yourself.
When appending to PersonInfo2 we have to repeat the anonymous struct type for every value we want to append, it is probably better to use PersonInfo as an array of type Person.
Go is using structural typing, that means, as long as the two types have the same underlying type, they are equivalent.
So, for your question: Person and struct{ ID int 'json:"id"'} is equivalent because they have the same underlying type, and therefore, PersonInfo and PersonInfo2 are also equivalent. I took of the json tags to simplify the example.
person1 := Person{1}
pStruct1 := struct{ID int}{2}
pInfo1 := PersonInfo{
person1,
pStruct1,
}
pInfo2 := PersonInfo2{
person1,
pStruct1,
}
fmt.Printf("%+v\n", pInfo1)
fmt.Printf("%+v", pInfo2);
//outputs
//PersonInfo: [{ID:1} {ID:2}]
//PersonInfo2: [{ID:1} {ID:2}]
Code example: https://play.golang.org/p/_wlm_Yfdy2
type PersonInfo is an object of Person, while PersonInfo2 is a class (or type in Golang) by itself. Even though their data structure is similar.
So, when you run DeepEqual() to check the similarity it will turn out to be false.
Example by previous comment:
if !reflect.DeepEqual(m,n) {
print("Not Equal")
}
Hope this helps.
I have a nested (not embedded) struct for which some of field types are arrays.
How can I check if an instance of this struct is empty? (not using iteration!!)
Note that there can't use StructIns == (Struct{}) or by an empty instance! This code have this error:
invalid operation: user == model.User literal (struct containing model.Configs cannot be compared)
user.Configs.TspConfigs:
type TspConfigs struct {
Flights []Flights `form:"flights" json:"flights"`
Tours []Tours `form:"tours" json:"tours"`
Insurances []Insurances`form:"insurances" json:"insurances"`
Hotels []Hotels `form:"hotels" json:"hotels"`
}
Those are slices, not arrays. It's important to emphasize as arrays are comparable but slices are not. See Spec: Comparision operators. And since slices are not comparable, structs composed of them (structs with fields having slice types) are also not comparable.
You may use reflect.DeepEqual() for this. Example:
type Foo struct {
A []int
B []string
}
f := Foo{}
fmt.Println("Zero:", reflect.DeepEqual(f, Foo{}))
f.A = []int{1}
fmt.Println("Zero:", reflect.DeepEqual(f, Foo{}))
Output (try it on the Go Playground):
Zero: true
Zero: false
I have two structs:
type person struct {
name string
age int
}
type class struct {
students []person
}
Lets say that in the main function, I create and populate two person variables and then I want to add them to a variable with class type. How can I do it?
I.e.
s := person{name: "Sean", age: 50}
t := person{name: "Nicola", age: 35}
how I can put s and t into:
lab:=class ?
The following should achieve what you want:
lab := class{[]person{s, t}}
Test it here.
Before you continue working on your project it's strongly recommended you read the following:
http://tour.golang.org/ (As Volker pointed out before me in the comments)
http://golang.org/doc/effective_go.html (After finishing the tour)
Is it valid C to declare a struct and define values enclosed in {}?
struct name new_name[] {
{"value1"},
{"value2"},
{"value3"},
}
Where:
struct name {
union {
char *value1;
} n_u;
char *value2;
}
What you've posted is invalid because it's missing an equals sign before the initializer (and also trailing semicolons). Otherwise, it's legal but somewhat hard to read because it doesn't initialize every field, and doesn't use a full set of braces. In a fully-braced initializer, you'll have a pair of braces around the list of values for every array, struct, or union. In this case you have an array of structs with unions in them, so there should be 3 levels of braces for optimum readability. An equivalent with everything spelled out is:
struct name new_name[] = {
{{"value1"}, NULL},
{{"value2"}, NULL},
{{"value3"}, NULL},
};