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
Related
I am new to learning Go and have a question around defining an argument that could be one of two types.
Take the code:
type Thing struct {
a int
b int
c string
d string
}
type OtherThing struct {
e int
f int
c string
d string
}
func doSomething(t Thing/OtherThing) error {
fmt.println(t.d)
return nil
}
As the structs have no functions I cannot write an interface for them at present.
So what is the Go idiomatic thing to do here? Is it just to bolt on a random function to the structs and write an interface or something else?
Thanks for the help...
Declare a interface with the common functionality for the two types. Use the interface type as the argument type.
// Der gets d values.
type Der interface {
D() string
}
type Thing struct {
a int
b int
c string
d string
}
func (t Thing) D() string { return t.d }
type OtherThing struct {
e int
f int
c string
d string
}
func (t OtherThing) D() string { return t.d }
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
You can give two structs some shared functionality by composing them both from a base struct:
package main
import (
"fmt"
)
// Der gets d values.
type Der interface {
D() string
}
type DBase struct {
d string
}
func (t DBase) D() string { return t.d }
type Thing struct {
DBase
a int
b int
c string
}
type OtherThing struct {
DBase
e int
f int
c string
}
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
func main() {
doSomething(Thing{DBase: DBase{"hello"}})
doSomething(OtherThing{DBase: DBase{"world"}})
}
DBase provides the field (d) and satisfies the Der interface the same way for both Thing and OtherThing. It does make the struct literal a little longer to define.
You can use an interface{} argument and the reflect package to access the common field. Many people will say that this approach is not idiomatic.
func doSomething(t interface{}) error {
d := reflect.ValueOf(t).FieldByName("d").String()
fmt.Println(d)
return nil
}
Try an example on the playground.
When my function is given an interface argument that is a pointer I would like to update the pointer to something else (a* = b*). If the function argument is not an interface and is instead a pointer, this works fine.
Given the following code:
package main
import "fmt"
type demoInterface interface {
GetName() string
}
type demoStruct struct {
name string
}
func (d demoStruct ) GetName() string {
return d.name
}
func Update(d1 demoInterface) {
fmt.Println(d1)
d2 := demoStruct{name: "bob"}
d1 = &d2
fmt.Println(d1)
}
func main() {
d1 := &demoStruct{name: "frank"}
fmt.Println(d1)
Update(d1)
fmt.Println(d1)
}
The output is
&{frank}
&{frank}
&{bob}
&{frank}
However I would actually expect
&{frank}
&{frank}
&{bob}
&{bob}
If I replace the Update function signature to accept a *demoStruct instead of a demoInterface it works as expected.
Is there a way to get this to work as expected when the functions signature is an interface rather than a pointer.
Thanks.
If you really need this, it could be one of the rare cases where a pointer to an interface may make sense. Here's your example modified with that:
package main
import "fmt"
type demoInterface interface {
GetName() string
}
type demoStruct struct {
name string
}
func (d demoStruct ) GetName() string {
return d.name
}
func Update(d1 *demoInterface) {
fmt.Println(*d1)
d2 := demoStruct{name: "bob"}
*d1 = d2
fmt.Println(*d1)
}
func main() {
d1 := demoInterface(demoStruct{name: "frank"})
fmt.Println(d1)
Update(&d1)
fmt.Println(d1)
}
Note that since Update takes *demoInterface, we can't just pass in *demoStruct (Go has no type covariance), so we have to convert the struct to the interface first.
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.
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?
I have been reading over the go-lang interface doc ; however it is still not clear to me if it is possible to achieve what I'd like
type A struct {
ID SomeSpecialType
}
type B struct {
ID SomeSpecialType
}
func (a A) IDHexString() string {
return a.ID.Hex()
}
func (b B) IDHexString() string {
return b.ID.Hex()
}
This will work fine; however I'd prefer some idiomatic way to apply the common method to both types and only define it once. Something Like:
type A struct {
ID SomeSpecialType
}
type B struct {
ID SomeSpecialType
}
func (SPECIFY_TYPE_A_AND_B_HERE) IDHexString() string {
return A_or_B.ID.Hex()
}
Essentialy you can't like you're used to, but what you can do is anonymously inherit a super-struct (sorry it's not the legal word :P):
type A struct {
}
type B struct {
A // Anonymous
}
func (A a) IDHexString() string {
}
B will now be able to implement the IDHexString method.
This is like in many other languages kind of the same as:
class B extends A { ... }
For example, using composition,
package main
import "fmt"
type ID struct{}
func (id ID) Hex() string { return "ID.Hex" }
func (id ID) IDHexString() string {
return id.Hex()
}
type A struct {
ID
}
type B struct {
ID
}
func main() {
var (
a A
b B
)
fmt.Println(a.IDHexString())
fmt.Println(b.IDHexString())
}
Output:
ID.Hex
ID.Hex