Reputation: 16395
I have the following struct in my package.
type Animal struct {
Id string
// and some more common fields
}
A user who uses my package should be able to implement own Animal
s. As I need Id
in one of my methods the user has to embed my struct.
type Dog struct {
Animal
Name string
Legs int
}
In my package I have a save()
function that saves Animal
s to database. As I don't know the user's type I have to use interface{}
as argument type. My question is: How do I get the Id
(from the parent struct Animal
)? At the moment I use some JSON parsing and unmarshalling, but is this the way to go/Go?
func put(doc interface{}) error {
res, err := json.Marshal(doc)
if err != nil {
return err
}
var animal *Animal
err = json.Unmarshal(res, &animal)
if err != nil {
return err
}
fmt.Println(animal.Id) // finally I have the Id
// ...
}
Usage
func main() {
bello := Dog{
Animal: Animal{
Id: "abcd1234",
},
Name: "bello",
Legs: 4,
}
err := put(bello)
// ...
}
Upvotes: 3
Views: 4649
Reputation: 36259
The way to go/Go here is to declare Animal
as an interface:
type Animal interface {
ID() int
Name() string
// Other Animal field getters here.
}
Then, save
can take Animal
as an argument and get all the info it needs using Animal
's methods.
The other possbile way is to use the reflect
package to obtain the Animal
fields from the struct, but this will be buggier, dirtier and possibly slower that using an interface.
Upvotes: 2
Reputation: 1328652
Maybe you can add an interface in order to be sure to get a reference to the parent struct:
type AnimalGetter interface {
GetAnimal() *Animal
}
func (dog *Dog) GetAnimal() *Animal {
return &dog.Animal
}
That would allow your save method to do a type assertion (AnimalGetter):
func save(obj interface{}) {
animal := obj.(AnimalGetter)
fmt.Printf("%v\n", animal.GetAnimal())
}
See a complete example in play.golang.org.
Output:
&{{dogid} wouf 0}
&{dogid}
Simpler:
func save(animal AnimalGetter) {
fmt.Printf("%v\n", animal.GetAnimal())
}
Upvotes: 4
Reputation: 49265
You can do it with this small reflection trick, although perhaps using interfaces like @VonC suggested might be a more practical and idiomatic approach.
Anyway, here's the same achieved with reflection:
func main() {
d := Dog {
Animal { "id1111" },
"Barky",
4,
}
fmt.Println(reflect.ValueOf(d).FieldByName("Animal").Interface().(Animal))
}
Upvotes: 1