I am new to Golang and I am trying to get a number of attributes from a structure
For example:
type Client struct{
name string//1
lastName string//2
age uint//3
}
func main(){
client := Client{name:"Facundo",lastName:"Veronelli",age:23}
fmt.println(client.getLengthAttibutes())//It would print "3"
}
Using the reflect package's ValueOf() function returns a value struct. This has a method called NumFields that returns the number of fields.
import (
"fmt"
"reflect"
)
type Client struct{
name string//1
lastName string//2
age uint//3
}
func main(){
client := Client{name:"Facundo",lastName:"Veronelli",age:23}
v := reflect.ValueOf(client)
fmt.Printf("Struct has %d fields", v.NumField())
}
You can use the reflect package for this:
import (
"fmt"
"reflect"
)
type Client struct {
name string //1
lastName string //2
age uint //3
}
func main() {
client := Client{name: "Facundo", lastName: "Veronelli", age: 23}
fmt.Println(reflect.TypeOf(client).NumField())
}
This is not, however, the size of that struct, only the number of fields. Use reflect.TypeOf(client).Size() to get how many bytes the struct occupies in memory.
Related
I would like to know if it is possible to get the name of a property from a structure and convert it to string.
For example in the following code:
package main
import "fmt"
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
//pass any attribute of any structure
fmt.Println(castProperty(StructB.RefStructA.ValueAA))
//print the name passed but in string. Do not print the value
//expected output: "StructB.RefStructA.ValueAA"
}
func castProperty(value interface{}) string {
//some code
}
Is it possible to write a function that allows obtaining the name of the property of a structure and converted to a string? property value is not required.
That's called Reflection. I let you read the page, it lets you do what you want.
First, read the The first law of reflection: https://go.dev/blog/laws-of-reflection
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}
https://play.golang.org/p/OuGgD1TlSMO
I am not sure exactly how do you want to give input to your function but here is an example that may help you
package main
import (
"log"
"reflect"
)
func main() {
getPropertyName(B{})
}
type A struct {
field1 string
}
type B struct {
field A
}
func getPropertyName(b interface{}) {
parentType := reflect.TypeOf(b)
val := reflect.ValueOf(b)
for i := 0; i< val.Type().NumField(); i++ {
t := val.Type().Field(i)
ty := val.Type().Field(i).Type.Name()
log.Println(parentType.Name()+"."+ t.Name+"."+ty)
}
}
you could do something like this :
package main
import (
"fmt"
)
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
x := &StructB{RefStructA: StructA{ValueAA: "something"}}
fmt.Printf("%+v", x)
}
out :
&{ValueBA: ValueBB: RefStructA:{ValueAA:something ValueAB:}}
I'm new to Golang and this could be so basic. Below is an example demonstrating my need. Junk should accept only id and name. Even though unmarshal eliminates extras, i need a way to hard stop execution stating json contain invalid key value pair. Could you please let me know if there's any.
package main
import (
"fmt"
"encoding/json"
)
type Junk struct{
ID int `json:"id"`
Name string `json:"name"`
Area string `json:"area"`
}
func main() {
a:=Junk{}
data:= `{"id":1,"name":"gg","junk":"Junk value"}`
err := json.Unmarshal([]byte(data),&a)
if err!=nil{
fmt.Println(err)
}
fmt.Println(a)
}
Use func (*Decoder) DisallowUnknownFields():
DisallowUnknownFields causes the Decoder to return an error when the
destination is a struct and the input contains object keys which do
not match any non-ignored, exported fields in the destination.
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Junk struct {
ID int `json:"id"`
Name string `json:"name"`
Area string `json:"area"`
}
func main() {
a := Junk{}
data := `{"id":1,"name":"gg","junk":"Junk value"}`
d := json.NewDecoder(strings.NewReader(data))
d.DisallowUnknownFields()
if err := d.Decode(&a); err != nil {
fmt.Println(err)
}
fmt.Println(a)
}
Try it out: https://play.golang.org/p/aTj2C-AAuZ7
For example, I have a struct that I take from the outside. I do not know the struct in fields and field values. I want to copy and use the same struct.
With reflection I find the fields and types in it. But how do I create this struct in the runtime?
Edit : I just want to create a struct in the same name as the runtime. Imagine I do not know my person type. I just want to create the same struct by reflection with interface.
I only know one interface. Person struct I just created it for instance. When a person creates a struct and sends it out, I will create it. instead of person, customer, student etc. You can send.
consider the following code as a 3rd party library.
package main
import(
"fmt"
"reflect"
)
type Person struct {
Id int
Name string
Surname string
}
func main(){
person := NewSomething()
newPerson := typeReflection(person)
ChangePerson(newPerson)
fmt.Println("Success")
}
func typeReflection(_person interface{}){
val := reflect.ValueOf(_person)
//How to create same struct
}
The github.com/mitchellh/copystructure library handles this operation, which is known as a deep copy. After performing a deep copy, the original and the copy contain the same data but modifications to either one do not affect the other.
package main
import (
"fmt"
"github.com/mitchellh/copystructure"
)
type Person struct {
Id int
Name string
Surname string
}
func main() {
original := Person{Id: 0, Name: "n", Surname: "s"}
copy := deepCopy(original)
// Change fields of the original Person.
original.Id = 9
fmt.Printf("original: %#v\n", original)
// The copy of the Person has not change, still has Id:0.
fmt.Printf("copy: %#v\n", copy)
}
func deepCopy(original interface{}) interface{} {
copy, err := copystructure.Copy(original)
if err != nil {
panic(err)
}
return copy
}
Here is the code that works:
package main
import (
"fmt"
)
type Base struct {
Field int
}
type Derived struct {
Base
}
func main() {
d := &Derived{}
d.Field = 10
fmt.Println(d.Field)
}
And here's the code that fails to compile with ./main.go:17: unknown Derived field 'Field' in struct literal
package main
import (
"fmt"
)
type Base struct {
Field int
}
type Derived struct {
Base
}
func main() {
d := &Derived{
Field: 10,
}
fmt.Println(d.Field)
}
What exactly is going on here? Sorry if it's obvious, but I just don't understand.
From the language specification:
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
So that's why it doesn't work.
Here are two possible ways to work around that limitation, each illustrated in the following function:
func main() {
d := &Derived{
Base{Field: 10},
}
e := new(Derived)
e.Field = 20
fmt.Println(d.Field)
fmt.Println(e.Field)
}
To initialize composed objects you have to initialize the embedded field, like any other object:
package main
import (
"fmt"
)
type Base struct {
Field int
}
type Derived struct {
Base
}
func main() {
d := &Derived{
Base{10},
}
fmt.Println(d.Field)
}
If I have a struct which I want to be able to Marhsal/Unmarshal things in and out of xml with (using encoding/xml) - how can I not print attributes which are empty?
package main
import (
"encoding/xml"
"fmt"
)
type MyThing struct {
XMLName xml.Name `xml:"body"`
Name string `xml:"name,attr"`
Street string `xml:"street,attr"`
}
func main() {
var thing *MyThing = &MyThing{Name: "Canister"}
result, _ := xml.Marshal(thing)
fmt.Println(string(result))
}
For example see http://play.golang.org/p/K9zFsuL1Cw
In the above playground I'd not want to write out my empty street attribute; how could I do that?
Use omitempty flag on street field.
From Go XML package:
a field with a tag including the "omitempty" option is omitted
if the field value is empty. The empty values are false, 0, any
nil pointer or interface value, and any array, slice, map, or
string of length zero.
In case of your example:
package main
import (
"encoding/xml"
"fmt"
)
type MyThing struct {
XMLName xml.Name `xml:"body"`
Name string `xml:"name,attr"`
Street string `xml:"street,attr,omitempty"`
}
func main() {
var thing *MyThing = &MyThing{Name: "Canister"}
result, _ := xml.Marshal(thing)
fmt.Println(string(result))
}
Playground