Dereference function interface argument when argument is a pointer - go

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.

Related

Golang idiom for passing multiple argument types

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.

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

Why my Golang defined method not implemented implicitily while String() does

In https://tour.golang.org/methods/11
It states Under the hood, interface values can be thought of as a tuple of a value and a concrete type
I define M as follows
script1
package main
import (
"fmt"
)
type I interface {
M() string
}
type T struct {
S string
w string
}
func (t T) M() string {
return "dddd"
}
func main() {
var i I
i = T{"Hello","eeee"}
fmt.Printf("(%v, %T)", i, i)
fmt.Println(i)
}
This prints out ({Hello eee}, main.T){Hello eee}
interface i has vaule {Hello eee} and type main.T
script2:
package main
import (
"fmt"
)
type I interface {
M() string
}
type T struct {
S string
w string
}
func (t T) M() string {
return "dddd"
}
func (t T) String() string {
return "ccccc"
}
func main() {
var i I
i = T{"Hello","eeee"}
fmt.Printf("(%v, %T)", i, i)
fmt.Println(i)
}
This prints out (ccccc, main.T)ccccc.
interface i has vaule ccccc and type main.T
Seems when i add String() as Stringer defined by the fmt package in script2. The String() is implemented implicitily,not sure why?
I thought in script2 i would have value "{Hello eee}" and type main.T
You should call fmt.Println(i.M()) ?
Why you want fmt call a function while its'n exist?
A Stringer is a type that can describe itself as a string. The fmt package (and many others) look for this interface to print values
Refer: https://golang.org/pkg/fmt/#Stringer
Stringer is implemented by any value that has a String method, which
defines the “native” format for that value. The String method is used
to print values passed as an operand to any format that accepts a
string or to an unformatted printer such as Print.
In your case, in script1 you are just printing out the struct. In script2 you are providing what the builder should use when an unformatted print occurs which is a function that prints out "ccccc".

How I can get return value based on argument type?

When I define function
func test(a int, b int) int {
//bla
}
I must set arguments and return value types. How I can return value based on argument type, ex
func test(argument type) type {
//if argument type == string, must return string
//or else if argument int, must return integer
}
Can I do this and how?
Go lacks generics, (not going to argue this point one way or the other), you can achieve this by passing interface{} to functions and then doing a type assertion on the other side.
package main
import "fmt"
func test(t interface{}) interface{} {
switch t.(type) {
case string:
return "test"
case int:
return 54
}
return ""
}
func main() {
fmt.Printf("%#v\n", test(55))
fmt.Printf("%#v", test("test"))
}
You will have to type assert the value you get out
v := test(55).(int)
Go does not yet have generics like C# or Java.
It does have an empty interface (interface{})
Here is code that I believe answers your question, if I understood it correctly:
package main
import (
"fmt"
"reflect"
)
type generic interface{} // you don't have to call the type generic, you can call it X
func main() {
n := test(10) // I happen to pass an int
fmt.Println(n)
}
func test(arg generic) generic {
// do something with arg
result := arg.(int) * 2
// check that the result is the same data type as arg
if reflect.TypeOf(arg) != reflect.TypeOf(result) {
panic("type mismatch")
}
return result;
}

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