Go struct field has same name as interface method - go

From a 3rd party:
package lib
type Bar interface{
Age() int
}
Foo(b Bar) int
This doesn't compile because Age is both a method name and field name:
package main
import "lib"
type Person struct {
Age int
}
func (p *Person)Age() int {
return p.Age
}
func main() {
p := Person()
lib.Foo(p)
}
Without renaming Person.Age, is there a way to call lib.Foo() on an instance of Person?

Well, not directly, of course, for the reasons already stated. But you could create a wrapper around Person, and pass that in:
type BarPerson struct {
*Person
}
func (bp *BarPerson) Age() int {
return bp.Person.Age
}
func main() {
p := Person{37}
lib.Foo(&BarPerson{&p})
}

Related

How to check if an attribute exists in an object's dynamic struct

I'm confused about how to check if an attribute exists in an object's dynamic struct. I.e. if we have the following structs:
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
And now I have a function using Animal as a parameter:
func checkAminalSpeed (a Animal){
// if the struct of current animal doesn't have the Speed attribute
// print ("I don't have a speed")
//otherwise, return the speed of this animal
}
This function is trying to check the varible's runtime type to choose action.
I'd like to know in this case, how to write this checkAminalSpeed function? Thanks!
Go does not support inheritance, but perhaps you'll find the following approach tolerable.
Use an interface to define the Animal's behaviour:
type Animal interface {
GetName() string
GetOrigin() string
GetSpeed() float32
}
Use a "base" type that will contain common fields and also implement the behaviour:
type AnimalBase struct {
Name string
Origin string
}
func (a AnimalBase) GetName() string { return a.Name }
func (a AnimalBase) GetOrigin() string { return a.Origin }
func (a AnimalBase) GetSpeed() float32 { return -1 }
Embed the "base" type and override any behaviour you need to:
type Bird struct {
AnimalBase
Speed float32
CanFly bool
}
func (b Bird) GetSpeed() float32 { return b.Speed }
And then...
func checkAminalSpeed(a Animal) {
if speed := a.GetSpeed(); speed == -1 {
fmt.Println("I don't have speed")
} else {
fmt.Println(speed)
}
}
https://play.golang.org/p/KIjfC7Rdyls
mkopriva is right. Go does not support inheritance, you can use reflect and interface{} also
ps: reflect cost more time than interface
package main
import (
"fmt"
"reflect"
)
type Animal struct {
Name string
Origin string
}
type Bird struct {
Animal
Speed float32
CanFly bool
}
type Bear struct {
Animal
Lazy bool
}
func checkAminalSpeed (a interface{}){
v := reflect.ValueOf(a)
if f, ok := v.Type().FieldByName("Speed"); ok{
fmt.Printf("%v\n", f)
}
}
func main() {
checkAminalSpeed(Bird{})
checkAminalSpeed(Bear{})
}

How to combine an interface and struct in golang?

package main
type A interface {
GetName() string
}
type B struct {
A
}
func (this *B) Func1() {
this.GetName()
}
type C struct {
B
}
func (this *C) GetName() string {
return "hello"
}
func main() {
var c = new(C)
c.GetName()
c.Func1()
}
https://play.golang.org/p/1X7yiQeie8F
My question:
c.Func1() will lead to:
panic: runtime error: invalid memory address or nil pointer dereference
My scenario is:
user needs to implement some basic interfaces of A, and then user can use the member function of B. I hope that complicate codes are encapsulated into the member function of B, and user just need to provide basic infos.
How to achieve this goal?
I see your code looping forever GetName calling duplicate
you can see my code
package main
import "fmt"
type A interface {
GetName() string
}
type B struct {
A
}
func (this *B) Func1() {
}
type C struct {
B
}
func (this *C) GetName() string {
return "hello"
}
func main() {
var c = new(C)
fmt.Println(c.GetName())
}
https://play.golang.org/p/PaFd-BS9sdP

GoLang defining methods on object receiver behaves wrong, but pointer receiver

I have an interface named Being, which requires two methods SetValue(v int) and GetValue() int. Then I have a base class Animal implementing it, and further a subclass Cat inherited from Animal.
Following is the code (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
func (a Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
func MakeCat() Being {
return Cat{}
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
However, the output is 0, rather than 1.
If I slightly modify the code to this (Go Playground):
package main
import (
"fmt"
)
type Being interface {
SetValue(v int)
GetValue() int
}
type Animal struct {
value int
}
type Cat struct {
Animal
}
//Change the receiver to a pointer
func (a *Animal) SetValue(v int) {
a.value = v
}
func (a Animal) GetValue() int {
return a.value
}
//Return the pointer
func MakeCat() Being {
cat := Cat{}
return &cat
}
func main() {
cat := MakeCat()
cat.SetValue(1)
fmt.Println(cat.GetValue())
}
where the modifications are marked by comments, the code behaves correctly, and output 1.
I cannot think of the reason of such phenomena, could anyone help?

Why does the SetAge() method not set the age correctly?

I'm experimenting with GoLang and interfaces and struct inheritence.
I've created a set of structures with the idea that I can keep common methods and values in a core structure an then just inherit this and add extra values as appropriate:
type NamedThing interface {
GetName() string
GetAge() int
SetAge(age int)
}
type BaseThing struct {
name string
age int
}
func (t BaseThing) GetName() string {
return t.name
}
func (t BaseThing) GetAge() int {
return t.age
}
func (t BaseThing) SetAge(age int) {
t.age = age
}
type Person struct {
BaseThing
}
func main() {
p := Person{}
p.BaseThing.name = "fred"
p.BaseThing.age = 21
fmt.Println(p)
p.SetAge(35)
fmt.Println(p)
}
Which you can also find here in the go playground:
https://play.golang.org/p/OxzuaQkafj
However when I run the main method, the age remains as "21" and isn't updated by the SetAge() method.
I'm trying to understand why this is and what I'd need to do to make SetAge work correctly.
Your function receiver's are value types, so they are copied into your function scope. To affect your received type past the lifetime of the function your receiver should be a pointer to your type. See below.
type NamedThing interface {
GetName() string
GetAge() int
SetAge(age int)
}
type BaseThing struct {
name string
age int
}
func (t *BaseThing) GetName() string {
return t.name
}
func (t *BaseThing) GetAge() int {
return t.age
}
func (t *BaseThing) SetAge(age int) {
t.age = age
}
type Person struct {
BaseThing
}
func main() {
p := Person{}
p.BaseThing.name = "fred"
p.BaseThing.age = 21
fmt.Println(p)
p.SetAge(35)
fmt.Println(p)
}

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