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?
Related
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{})
}
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
I'm pretty new to go. I'm trying to mock a single method of a struct using testify, but I don't know how to do it.
Here's the code:
type HelloWorlder interface {
SayHello() string
GetName() string
}
type HelloWorld struct{}
func (hw *HelloWorld) SayHello() string {
return fmt.Sprintf("Hello World from %s!", hw.GetName())
}
func (hw *HelloWorld) GetName() string {
return "se7entyse7en"
}
and here's the test:
type MockHelloWorld struct {
mock.Mock
HelloWorld
}
func (m *MockHelloWorld) GetName() string {
args := m.Called()
return args.String(0)
}
type SomeTestSuite struct {
suite.Suite
}
func (s *SomeTestSuite) TestMocking() {
mhw := new(MockHelloWorld)
mhw.On("GetName").Return("foo bar")
fmt.Println(mhw.SayHello())
}
The idea is to mock only the GetName method so that it prints Hello World from foo bar!. Is that possible?
For those familiar with Python, what I'm trying to achieve is similar to what the unittest.Mock class permits through the wraps argument.
UPDATE
The imported packages from testify are these:
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
Maybe this will help you.
package main
import (
"fmt"
"github.com/stretchr/testify/mock"
)
type userReader interface {
ReadUserInfo(int) int
}
type userWriter interface {
WriteUserInfo(int)
}
type UserRepository struct {
userReader
userWriter
}
type realRW struct{}
func (db *realRW) ReadUserInfo(i int) int {
return i
}
func (db *realRW) WriteUserInfo(i int) {
fmt.Printf("put %d to db.\n", i)
}
// this is mocked struct for test writer.
type MyMockedWriter struct {
mock.Mock
}
func (m *MyMockedWriter) ReadUserInfo(i int) int {
args := m.Called(i)
return args.Int(0)
}
func main() {
rw := &realRW{}
repo := UserRepository{
userReader: rw,
userWriter: rw,
}
fmt.Println("Userinfo is:", repo.ReadUserInfo(100))
repo.WriteUserInfo(100)
// when you want to write test.
fmt.Println("Begin test....................")
testObj := new(MyMockedWriter)
testObj.On("ReadUserInfo", 123).Return(250)
testRepo := UserRepository{
userReader: testObj,
userWriter: rw,
}
fmt.Println("Userinfo is:", testRepo.ReadUserInfo(123))
testRepo.WriteUserInfo(100)
}
// Output:
// Userinfo is: 100
// put 100 to db.
// Begin test....................
// Userinfo is: 250
// put 100 to db.
Good luck.
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})
}
I'm trying to add a pointer to a struct to a slice, but I can't get rid of this error:
cannot use NewDog() (type *Dog) as type *Animal in append:
*Animal is pointer to interface, not interface
How can I avoid this error? (while still using pointers)
package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]*Animal, 2)
pets[0] = NewDog()
(*pets[0]).Speak()
}
package main
import "fmt"
type Animal interface {
Speak()
}
type Dog struct {
}
func (d *Dog) Speak() {
fmt.Println("Ruff!")
}
func NewDog() *Dog {
return &Dog{}
}
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
You don't need a Slice of pointers to Animal interfaces.
http://golang.org/doc/effective_go.html#pointers_vs_values
just change your code to:
func main() {
pets := make([]Animal, 2)
pets[0] = NewDog()
pets[0].Speak()
}
a interface value is already an implicit pointer.