Golang embedded struct type - go

I have these types:
type Value interface{}
type NamedValue struct {
Name string
Value Value
}
type ErrorValue struct {
NamedValue
Error error
}
I can use v := NamedValue{Name: "fine", Value: 33}, but I am not able to use e := ErrorValue{Name: "alpha", Value: 123, Error: err}
Seems that embedding syntax was ok, but using it doesn't work?

Embedded types are (unnamed) fields, referred to by the unqualified type name.
Spec: Struct types:
A field declared with a type but no explicit field name is an anonymous field, also called an embedded field or an embedding of the type in the struct. An embedded type must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
So try:
e := ErrorValue{NamedValue: NamedValue{Name: "fine", Value: 33}, Error: err}
Also works if you omit the field names in the composite literal:
e := ErrorValue{NamedValue{"fine", 33}, err}
Try the examples on the Go Playground.

For deeply nested structs, the accepted answer's syntax is a little verbose. For example, this :
package main
import (
"fmt"
)
type Alternative struct {
Question
AlternativeName string
}
type Question struct {
Questionnaire
QuestionName string
}
type Questionnaire struct {
QuestionnaireName string
}
func main() {
a := Alternative{
Question: Question{
Questionnaire: Questionnaire{
QuestionnaireName: "q",
},
},
}
fmt.Printf("%v", a)
}
(Go playground)
Could be rewritten like this:
a := Alternative{}
a.QuestionnaireName = "q"

In addition to the wonderful answer by icza.
you can simply do this:
v := NamedValue{Name: "fine", Value: 33}
e := ErrorValue{NamedValue:v, Error: err}
and it works just fine. checkout the example Here

Related

go when to use & or not?

I am confused whether to use a & with go when declaring a variable and init with a struct
say we have a struct wrapper
type HttpResult struct {
Status int32 `json:"status"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
}
and a struct defining the user model
type OmUser struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name"`
Password string `json:"password"`
Email string `json:"email"`
}
And the following declaring seems give the same result:
myOmUser := OmUser{ //note no & sign here
Name: "Tony",
Password: "mypass",
Email: "tony#foo.com"
}
httpResult := &HttpResult{
Status: 0,
Msg: "ok",
Data: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
Or
myOmUser := &OmUser{ //note the & sign
Name: "Tony",
Password: "mypass",
Email: "tony#foo.com"
}
httpResult := &HttpResult{
Status: 0,
Msg: "ok",
Data: myOmUser,
}
js, _ := json.Marshal(httpResult)
fmt.Println(js)
so, when to use & and why?
In your particular example it doesn't make a difference.
But when we look at an example of using json.Unmarshal() it makes a bit more sense:
jsonBlob := []byte(`{"id": "1", "name": "bob", "password": "pass", "email", "hi#me.com"}`)
var newOmUser OmUser
err := json.Unmarshal(jsonBlob, &newOmUser)
if err != nil {
panic(err)
}
Here we declare the variable before hand, and then we use the & to pass a pointer to that variable into the Unmarshal function.
That means that the Unmarshal function can reach out and update that variable, even though it's declared outside of the function.
Without the &, the Unmarshal function would get a copy of the newOmUser variable, and it would leave the original newOmUser variable that we declared empty.
When it comes to pointers, my general rule of thumb is:
Don't use them unless you have to.
If you need to use any unmarshalling functions, you'll need them. There are lots of other functions that make use of them.
Here's a quick exercise that helps me understand a little more about pointers:
func uppercase(s string) {
s = strings.ToUpper(s)
fmt.Println(s)
}
// Same as the uppercase() function, but works with a pointer.
func uppercasePointer(s *string) {
*s = strings.ToUpper(*s)
fmt.Println(*s)
}
name := "bob"
uppercase(name) // prints 'BOB'
fmt.Println(name) // prints 'bob' - our variable was not changed
name2 := "bobpointer"
uppercasePointer(&name2) // prints 'BOBPOINTER'
fmt.Println(name2) // prints 'BOBPOINTER' - our variable was changed
When we call the uppercase(name) function, go makes a copy of the name variable and sends it to the uppercase function.
Whatever the function does to that copy that it received stays in the function. The original variable that we declared outside the function is not changed.
When we call the uppercasePointer(&name2) function, we are sending a pointer to the name2 variable we declared.
The function can use that pointer to reach out and update the name2 variable that we declared earlier.
At first, you might not see the point of pointers, but as you continue to use go, you will see that they help us solve some complex problems.
Empty interface type in Go can hold values of any type. Tour here.
So in your HttpResult.Data is an empty interface type. So you can assigne any type to it.
The difference between defining a variable with & is getting a pointer of that type. Tour here.
Those are obviously two types with two different functionalities in Go. But you can assign both to empty interface type variable because its accepting values of any type.
package main
import (
"fmt"
"reflect"
)
type OmUser struct {
}
func main() {
myOmUser := OmUser{}
myOmUser2 := &OmUser{}
fmt.Println(reflect.TypeOf(myOmUser)) //main.OmUser
fmt.Println(reflect.TypeOf(myOmUser2)) //*main.OmUser
}
For more details about &, read Go doc address operators
For an
operand x of type T, the address operation &x generates a pointer of
type *T to x. The operand must be addressable, that is, either a
variable, pointer indirection, or slice indexing operation; or a field
selector of an addressable struct operand; or an array indexing
operation of an addressable array. As an exception to the
addressability requirement, x may also be a (possibly parenthesized)
composite literal. If the evaluation of x would cause a run-time
panic, then the evaluation of &x does too.
fooA := &Foo{}
fooA has type *Foo.
fooB := Foo{}
fooB has type Foo.
https://tour.golang.org/moretypes/1
In practice, this means if you had a func that accepted type *Foo you could do either of the following...
func someFunc(f *Foo) {
// ...
}
fooA := &Foo{}
someFunc(fooA)
fooB := Foo{}
someFunc(&fooB)
So realistically, create whichever you need to be honest.

Implicit type with struct of slices

If I have a file like this:
package main
import "fmt"
type Language struct {
Example []string
Link []string
}
func main() {
o := Language{
{".go", "go.ps1"},
{"golang.org", "go.dev"},
}
fmt.Println(o)
}
I get this result:
missing type in composite literal
I found I can resolve like this:
[]string{".go", "go.ps1"},
[]string{"golang.org", "go.dev"},
but is that strictly required? I would think Go would know the type of each
property based on the struct definition.
The problem here is not that the compiler doesn't know the type, it is that the syntax for a composite literal requires the type:
https://golang.org/ref/spec#Composite_literals
A string array literal is []string{"a","b",","c"}, not {"a","b","c"}.
You need field in struct definition, like this
o := Language{
Example: []string{".go", "go.ps1"},
Link: []string{"golang.org", "go.dev"},
}
fmt.Println(o)

How do I use reflect to check if the type of a struct field is interface{}?

I am using the reflect package to determine the type of a struct field is interface{}
I want to do the comparison like so (where t is a reflect.Type):
if t == reflect.TypeOf(interface{}) {
}
The problem is that the compiler complains: type interface {} is not an expression.
Is there anyway to check if the type of a struct field is an interface{}?
You can get the type of the interface Y by creating a nil instance and using reflection:
yType := reflect.TypeOf((*Y)(nil)).Elem()
and then use the expression
reflect.TypeOf(x).Implements(yType)
to check if the type implements the interface.
Interfaces themselves can not be instantiated. The interface{} interface which is the empty interface is implemented by all types so all fields implement that.
https://play.golang.org/p/gRfheIW_9Y
Actually it also works with the empty interface{} itself but this will always return true (if i'm not missing something):
https://play.golang.org/p/29rWP4LtIo
interface{} is a type, and reflect.TypeOf() expects a value. So you can't pass the literal interface{} to it. You can only pass a value.
Back to the original question. Let's see a struct example:
type My struct {
A int
B interface{}
C io.Reader
}
You want to tell if the type of a field is interface{}. Acquire the reflect.Type of the struct type, then you can access the fields using Type.Field() or Type.FieldByName().
This gives you a value of type reflect.StructField which stores the type of the field.
So far so good. But what should we compare it to? interface{} is an interface type with 0 methods. You can't have (instantiate) a value of that type. You can only have values of concrete types, but yes, they may be wrapped in an interface type.
You could use Type.Kind, and compare it to reflect.Interface, which tells you if it's an interface, but this is true for all interface types. You could also check if it has 0 methods with Type.NumMethod(), which must be 0 for interface{}, but other interfaces could also have 0 methods...
You may use Type.Name, but since interface{} is a unnamed type, its name is the empty string "" (and there are other unnamed types). You may use Type.String() which returns "interface {}" for the empty interface:
t := reflect.TypeOf(My{})
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("Field %q, type: %-12v, type name: %-8q, is interface{}: %v\n",
f.Name, f.Type,
f.Type.Name(),
f.Type.String() == "interface {}",
)
}
Output (try it on the Go Playground):
Field "A", type: int , type name: "int" , is interface{}: false
Field "B", type: interface {}, type name: "" , is interface{}: true
Field "C", type: io.Reader , type name: "Reader", is interface{}: false
You might find this related question interesting / useful: Identify non builtin-types using reflect

Exporting functions with anonymous struct as a parameter [cannot use value (type struct {...}) as type struct {...} in argument to package.Func]

Here is a piece of code play.google.org that runs without any problem:
package main
import (
"fmt"
)
func PrintAnonymous(v struct {
i int
s string
}) {
fmt.Printf("%d: %s\n", v.i, v.s)
}
func PrintAnonymous2(v struct{}) {
fmt.Println("Whatever")
}
func main() {
value := struct {
i int
s string
}{
0, "Hello, world!",
}
PrintAnonymous(value)
PrintAnonymous2(struct{}{})
}
However, if the PrintAnonymous() function exists in another package (let's say, temp), the code will not work:
cannot use value (type struct { i int; s string })
as type struct { i int; s string } in argument to temp.PrintAnonymous
My question are:
Is there a way to call a (public) function with anonymous struct as a parameter (a.k.a. PrintAnonymous() above)?
A function with empty struct as a parameter (a.k.a. PrintAnonymous2() above) can be called even if it exists in another package. Is this a special case?
Well, I know that I can always name the struct to solve the problem, I'm just curious about this, and wonder why it seems that this is not allowed.
The fields of your anonymous struct type are unexported. This means you cannot create values of this struct and specify values for the fields from another package. Spec: Composite literals:
It is an error to specify an element for a non-exported field of a struct belonging to a different package.
If you change the struct definition to export the fields, then it will work because all fields can be assigned to by other packages (see Siu Ching Pong -Asuka Kenji-'s answer).
This is the case with the empty struct (with no fields) too: the empty struct has no fields, thus it has no unexported fields, so you're allowed to pass a value of that.
You can call the function with unmodified struct (with unexported fields) via reflection though. You can obtain the reflect.Type of the PrintAnonymous() function, and you can use Type.In() to get the reflect.Type of its first parameter. That is the anonymous struct we want to pass a value for. And you can construct a value of that type using reflect.New(). This will be a reflect.Value, wrapping a pointer to the zero value of the anonymous struct. Sorry, you can't have a struct value with fields having non-zero values (for reason mentioned above).
This is how it could look like:
v := reflect.ValueOf(somepackage.PrintAnonymous)
paramt := v.Type().In(0)
v.Call([]reflect.Value{reflect.New(paramt).Elem()})
This will print:
0:
0 is zero value for int, and "" empty string for string.
For deeper inside into the type system and structs with unexported fields, see related questions:
Identify non builtin-types using reflect
How to clone a structure with unexported field?
Interestingly (this is a bug, see linked issue below), using reflection, you can use a value of your own anonymous struct type (with matching, unexported fields), and in this case we can use values other than the zero value of the struct fields:
value := struct {
i int
s string
}{
1, "Hello, world!",
}
v.Call([]reflect.Value{reflect.ValueOf(value)})
Above runs (without panic):
1: Hello, world!
The reason why this is allowed is due to a bug in the compiler. See the example code below:
s := struct{ i int }{2}
t := reflect.TypeOf(s)
fmt.Printf("Name: %q, PkgPath: %q\n", t.Name(), t.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t.Field(0).Name, t.Field(0).PkgPath)
t2 := reflect.TypeOf(subplay.PrintAnonymous).In(0)
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Name(), t2.PkgPath())
fmt.Printf("Name: %q, PkgPath: %q\n", t2.Field(0).Name, t2.Field(0).PkgPath)
Output is:
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
Name: "", PkgPath: ""
Name: "i", PkgPath: "main"
As you can see the unexported field i in both anonymous struct types (in main package and in somepackage as parameter to PrintAnonymous() function) –falsely– report the same package, and thus their type will be equal:
fmt.Println(t == t2) // Prints true
Note: I consider this a flaw: if this is allowed using reflection, then this should be possible without using reflection too. If without reflection the compile-time error is justified, then using reflection should result in runtime panic. I opened an issue for this, you can follow it here: issue #16616. Fix currently aims Go 1.8.
Oh! I just realized that the field names are in lowercase, and thus not public! Changing the first letter of the field names to uppercase solves the problem:
package main
import (
"temp"
)
func main() {
value := struct {
I int
S string
}{
0, "Hello, world!",
}
temp.PrintAnonymous(value)
temp.PrintAnonymous2(struct{}{})
}
package temp
import (
"fmt"
)
func PrintAnonymous(v struct{I int; S string}) {
fmt.Printf("%d: %s\n", v.I, v.S)
}
func PrintAnonymous2(v struct{}) {
fmt.Println("Whatever")
}

Go YAML parser failing silently

I'm trying to get simple YAML parsing in go working with gopkg.in/yaml.v2.
From the documentation:
Maps and pointers (to a struct, string, int, etc) are accepted as
out values. If an internal pointer within a struct is not
initialized, the yaml package will initialize it if necessary
for unmarshalling the provided data. The out parameter must not be nil.
The type of the decoded values should be compatible with the
respective values in out. If one or more values cannot be decoded
due to a type mismatches, decoding continues partially until the
end of the YAML content, and a *yaml.TypeError is returned with
details for all missed values.
Note the important bits here: "pointer within struct initialized if nec'y", and "yaml.TypeError returned if a value can't be decoded".
Now:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type YamlTypeA struct {
D string `yaml: "d"`
E string `yaml: "e"`
}
type YamlTypeB struct {
F string `yaml: "f"`
}
type YamlTypeC struct {
TypeA *YamlTypeA `yaml: "a"`
TypeB []YamlTypeB `yaml: "b"`
}
func main() {
var yamlObj YamlTypeC
text := []byte(`
---
a:
d: foo
e: bar
b: [{f: "fails"},
{f: "completely"}]
`)
err := yaml.Unmarshal(text,&yamlObj)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("OK")
fmt.Printf("TypeA.D: %s\n", yamlObj.TypeA.D)
fmt.Printf("I have %d TypeB\n", len(yamlObj.TypeB))
}
yields
OK
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x4014b3]
which appears to violate the promises made in the documentation jointly. If I make the nested YamlTypeA immediate instead of a pointer, the result is that the output value is not touched, still no error:
OK
TypeA.D:
I have 0 TypeB
What gives here? Is it just broken / poorly documented? How can you get nested struct values to parse out of YAML? (Using maps of maps is cumbersome and not at all a solution here.)
You have spaces in your struct tags, so they're being ignored:
type YamlTypeA struct {
D string `yaml:"d"`
E string `yaml:"e"`
}
type YamlTypeB struct {
F string `yaml:"f"`
}
type YamlTypeC struct {
TypeA *YamlTypeA `yaml:"a"`
TypeB []YamlTypeB `yaml:"b"`
}

Resources