get name from struct passed to function - go

How to get the name of an struct/interface?
pkg
package crud
type User struct {
ID uint
Name string
Email string
}
main
package main
import "./crud"
func get_struct(value interface{}){
// print "User"
}
func main(){
get_struct(&crud.User{})
}

The reflect package provides this; you simply create a new reflect.Value from the variable and inspect its type:
func get_struct(value interface{}){
var name string
ref := reflect.ValueOf(value)
if ref.IsValid() {
name = ref.Type().Name()
} else {
name = "nil"
}
fmt.Println(name)
}
Note: you may not get the output you want if a pointer is passed. You may want to consider using Type.String() over Type.Name().
Playground

Related

How to create a variable of dynamic type

I am able to create a variable 'model' of type 'Sample' as follows:
type Sample struct {
Id int `jsonapi:"attr,id,omitempty"`
Name string `jsonapi:"attr,name,omitempty"`
}
var model Sample // created successfully
I am able to create it successfully as I already know the struct type (Sample).
However, when I tried to create a similar variable 'a' as follows, I get syntax error:
package main
import (
"fmt"
"reflect"
)
type Sample struct {
Id int `jsonapi:"attr,id,omitempty"`
Name string `jsonapi:"attr,name,omitempty"`
}
func test(m interface{}) {
fmt.Println(reflect.TypeOf(m)) // prints 'main.Sample'
var a reflect.TypeOf(m) // it throws - syntax error: unexpected ( at end of statement
}
func main() {
var model Sample // I have created a model of type Sample
model = Sample{Id: 1, Name: "MAK"}
test(model)
}
Please advise how to create a variable of dynamic type in Go.
package main
import (
"fmt"
"reflect"
)
type Sample struct {
Id int `jsonapi:"attr,id,omitempty"`
Name string `jsonapi:"attr,name,omitempty"`
}
func test(m interface{}) {
fmt.Println(reflect.TypeOf(m)) // prints 'main.Sample'
a, ok := m.(main.Sample)
if ok {
fmt.Println(a.Id)
}
}
func main() {
var model Sample // I have created a model of type Sample
model = Sample{Id: 1, Name: "MAK"}
test(model)
}
and if you want a little more dynamism, you can use a type switch. Instead of the a, ok := m.(main.Sample), you do
switch a := m.(type) {
case main.Sample:
fmt.Println("It's a %s", reflect.TypeOf(m))
case default:
fmt.Println("It's an unknown type")
}

Modify struct fields during instance generation

Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.

How to make parameter of function is a "generic" struct

For example, I want to write a method like this:
func parseData(rawData []json.RawMessage) []interface{} {
var migrations []interface{}
for _, migration := range rawData {
// this is an custom struct
command := UserCommand{}
json.Unmarshal(migration, &command)
migrations = append(migrations, command)
}
return migrations
}
The problem of this code is: If I don't want to parse UserCommand but any other such as ProductCommand, I must write the same code, only different at line: command := UserCommand{}. So my question is: how can I generic this code.
I have tried this solution but it doesn't work:
func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
var migrations []interface{}
for _, migration := range rawData {
command := class
json.Unmarshal(migration, &command)
migrations = append(migrations, command)
}
return migrations
}
// then I call this method
parseData(data, UserCommand{})
But it doesn't work. It return array of map[string]interface{} How can I fix this.
Edit:
Here is some my defined struct
type UserCommand struct {
User string
Info string
}
type ProductCommand struct {
Name string
Quanlity int
}
// I want to be able to call this method
parseData(data, UserCommand{})
It is possible to support this style of "generic" signature by using Go's reflect package.
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type UserCommand struct {
User string
Info string
}
type ProductCommand struct {
Name string
Quantity int
}
func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
var parsed []interface{}
for _, elem := range rawData {
// Create a pointer to a new zero value of the same type as `class`.
command := reflect.New(reflect.TypeOf(class))
// Pass a pointer to the new value to `json.Unmarshal`.
json.Unmarshal(elem, command.Interface())
// Insert the pointed-to new value into the output slice.
parsed = append(parsed, command.Elem().Interface())
}
return parsed
}
func main() {
data := []json.RawMessage{
json.RawMessage(`{"User":"u1","Info":"i1"}`),
json.RawMessage(`{"User":"u2","Info":"i2"}`),
}
parsed := parseData(data, UserCommand{})
fmt.Printf("%#v\n", parsed)
data = []json.RawMessage{
json.RawMessage(`{"Name":"n1","Quantity":1}`),
json.RawMessage(`{"Name":"n2","Quantity":2}`),
}
parsed = parseData(data, ProductCommand{})
fmt.Printf("%#v\n", parsed)
}
The output shows that the first parseData call has parsed two UserCommand structs and the second call has parsed two ProductCommand structs.
[]interface {}{main.UserCommand{User:"u1", Info:"i1"}, main.UserCommand{User:"u2", Info:"i2"}}
[]interface {}{main.ProductCommand{Name:"n1", Quantity:1}, main.ProductCommand{Name:"n2", Quantity:2}}

Create constructor for different go structs

I have a struct which I initiate in some process like following, and this is working as expected.
This is specific runner
type TestRunner struct {
path string
name string
}
func NewRunner(p string, n string) *TestRunner {
return &TestRunner{
path: p,
name: n,
}
}
Now I want in the same package to create another runner so I do it like this e.g.
Also specific runner
type TestRunner2 struct {
path string
name string
}
func NewRunner(p string, n string) *TestRunner2 {
return &TestRunner2{
path: p,
name: n,
}
}
Now I get error that the func NewRunner is exist
I have another file (in the same package) which include the interface
This is generic implementation (different file in the same package)
type Runner interface {
Run(path string) error
ChangePath(newPath string)
}
So maybe the NewRunner should be there, where its recommended to put the new object ?
obviously I can create NewRunner1 and NewRunner2 method in the file but im not sure if it’s recommended
First, you should name your runners according to their functionality, not by number. FastRunner and SlowRunner or LocalRunner vs RemoteRunner. You get the idea. Then you should create a construct for each one:
func NewFastRunner( ... ) *FastRunner {
return &FastRunner{ ... }
}
func NewSlowRunner( ... ) *SlowRunner {
return &SlowRunner{ ... }
}
This is standard practice, and makes for very readable, unambiguous code.
You can use method pointer type receivers for each runner and then implement interface. That way you need not to return any thing you can directly assign values like path and name to runner using pointer.
package main
import (
"fmt"
)
type TestRunner1 struct {
path string
name string
}
type TestRunner2 struct {
path string
name string
}
type Runner interface {
Run(path string) error
ChangePath(newPath string)
}
func (tr1 *TestRunner1) NewRunner(p string, n string) {
tr1.path = p
tr1.path = n
}
func (tr2 *TestRunner2) NewRunner(p string, n string) {
tr2.path = p
tr2.path = n
}
func main() {
fmt.Println("Hello, playground")
}
Check the code here

Object Factory in golang

I am a new to golang. I need to design a function to create object of differing types based on input. But I failed to figure out how to design the interface. Here comes my code:
package main
import (
"fmt"
)
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(type int) *AA {
if type ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(0)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}
The compiler tells me error no matter I ask ObjectFactory return *AA or interface{}. How can I make it work?
First off, using type as a variable name is disallowed in go (see the spec). That is your first problem.
The return type of object factory is *AA. This means that it can only return variables of type *AA, which causes the return of type of BB to fail. As defined in the spec, go doesn't have type inheritance, just struct embedding.
If you create an interface called sayer, you can use that instead of *AA in your ObjectFactory function.
type sayer interface {
say()
}
You probably want to use this interface when trying to get multiple dispatch (as demonstrated in the code below (see on play.golang.org as well).
Try this code:
package main
import (
"fmt"
)
type sayer interface {
say()
}
type AA struct{
name string
}
func (this *AA) say(){
fmt.Println("==========>AA")
}
type BB struct{
*AA
age int
}
func (this *BB) say(){
fmt.Println("==========>BB")
}
func ObjectFactory(typeNum int) sayer {
if typeNum ==1 {
return new(AA)
}else{
return new(BB)
}
}
func main() {
obj1 := ObjectFactory(1)
obj1.say()
obj2 := ObjectFactory(0)
obj2.say()
}

Resources