Cannot use struct that implements interface [duplicate] - go

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 4 years ago.
code:
package main
import "fmt"
type implementation struct {
d []int
}
func (impl *implementation) getData() interface{} {
return impl.d
}
type phase struct{}
type data interface {
getData() interface{}
}
func MakeIntDataPhase() *phase {
return &phase{}
}
func (p *phase) run(population []data) []data {
return nil
}
func main() {
var population []implementation
MyPhase := MakeIntDataPhase()
fmt.Println(MyPhase.run(population))
}
When running following code in playground I got following error: prog.go:30:25: cannot use population (type []implementation) as type []data in argument to MyPhase.run
I am new to golang and I don't understand why is this happening?
Struct implementation implements method getData() from data interface. Isn't it enough to use a slice of implementation in run method?
Where my reasoning is wrong?

This seems counter-intuitive but []data is of a different type to []implementation because of how slice types are represented in Go.
This is actually discussed in the the Go Wiki
Edit: Consider this
var impl []*implementation
var data []data = impl
The compiler will complain with
cannot use impl (type []*implementation) as type []data in assignment
It's more code but you actually have to create a slice of your interface as what the comments in this thread recommends, like so:
var impl []*implementation
var data []data
// assuming impl already has values
for _, v := range impl {
data = append(data, v)
}

Related

Initialize value for pointer in Go Generics [duplicate]

This question already has answers here:
How can I instantiate a non-nil pointer of type argument with generic Go?
(4 answers)
What is the generic type for a pointer that implements an interface?
(2 answers)
Closed 9 months ago.
I have a generic func func foo[T bar]() which I need to pass a type which is a pointer to a struct foo[*zab](). In func foo I want to initialize the value using one of new() or var t T.
My question is if that is possible and if, how! See the code below (with link to Go playground):
package main
import "fmt"
func main() {
foo[*zab]()
}
type bar interface {
String() string
SetString(string)
}
func foo[T bar]() {
var t T
t.SetString("asdf")
fmt.Println(t.String()) // Should return "asdf"
}
type zab struct {
f string
}
func (z zab) String() string {
return z.f
}
func (z *zab) SetString(f string) {
z.f = f
}
https://go.dev/play/p/rLCuvYNem1t

How can a method take an output parameter of an interface type? [duplicate]

This question already has an answer here:
Set reference in Go
(1 answer)
Closed 3 years ago.
Given:
type Savable interface {}
type Customer struct {} // satisfies 'Savable'
func GetSaved(id string, s Savable) {
// somehow get a reference to the object from cache
s = cachedObject
// alternately, something like:
// json.Unmarshal(jsonFromDisk, &s)
}
func Foo() {
c := Customer{}
GetSaved("bob", &c)
}
Trying a few configurations, I either get compilation errors related to "Expects *Savable, found *Customer", or the GetSaved function doesn't actually change what I want to be the 'output variable'. Is this doable, and I'm just not getting the right mix of interface/pointers/etc? Or is this not possible for some reason?
Edit: A working example illustrating the problem.
You can use reflection to set the passed interface.
Even when a struct reference is passed as interface, the underlying type info is not lost and we can use reflection.
package main
import (
"fmt"
"reflect"
)
type Savable interface {}
type Customer struct {
Name string
}
func GetSaved(id string, s Savable) {
cached := Customer{ Name: id }
c1 := reflect.ValueOf(cached)
reflect.ValueOf(s).Elem().Set(c1)
}
func main() {
c := Customer{}
fmt.Printf("Before: %v\n", c)
GetSaved("bob", &c)
fmt.Printf("After: %v\n", c)
}
Here is the running link
This works I converted it to bytes and Unmarshaled it back into your structure. Hope this helps. :)
package main
import (
"encoding/json"
"fmt"
)
type Savable interface{}
type Customer struct {
Name string
} // satisfies 'Savable'
func GetSaved(id string, s Savable) {
// somehow get a reference to the object from cache
cached := Customer{Name: "Bob"}
byt, _ := json.Marshal(cached)
_ = json.Unmarshal(byt, &s)
}
func main() {
c := Customer{}
GetSaved("bob", &c)
fmt.Println(c)
}
Run link: https://play.golang.org/p/NrBRcRmXRVZ

Effectively wrapping public sdk types in golang

I am using pagerduty go sdk to do a bunch of api requests.
Particularly I am making use of
func NewClient(authToken string) *Client
to create a new Client type. I want to add some utility functions to my own work to *Client. I tried doing this:
type BetterPdClient *pagerduty.Client
func NewClient(auth string) BetterPdClient {
return pagerduty.NewClient(auth)
}
func (b *BetterPdClient) DoSomething() {
b.GetIncident(....)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
pd_client.DoSomething()
}
But I get the following error:
invalid receiver type *BetterPdClient (BetterPdClient is a pointer type)
I understand that DoSomething() is expecting a pointer as caller. Only other way I could think of is sending the ptr as a function argument:
func NewClient(auth string) *pagerduty.Client {
return pagerduty.NewClient(auth)
}
func DoSomething(cl *pagerduty.Client) {
fmt.Println(cl)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
DoSomething(pd_client)
}
Is there a better way?
Declaring a type as a pointer to another type is almost never what you want because Go doesn't allow you to add methods to that new type, nor to the pointer of that type as you've already figured out yourself. This one doesn't compile either:
type T struct{}
type P *T
func (P) M() {}
If you want to "extend" a type without "hiding" it's existing functionality your best bet is to embed it in a struct.
type T struct{
// ...
}
func (T) M() {}
type U struct {
*T
}
func NewU() *U {
return &U{&T{}}
}
func (U) N() {}
func main() {
u := NewU()
u.M()
u.N()
}
And what I mean by "hiding existing functionality" is that when you define a new type in terms of another, already existing type, your new type will not get direct access to the methods of the existing type. All you're doing is just saying that your new type should have the same structure as the already existing type. Although it's worth pointing out that this property gives you the ability to convert one type to the other...
type T struct{
// ...
}
func (T) M() {}
type U T
func NewU() *U {
return &U{}
}
func (U) N() {}
func main() {
u := NewU()
u.M() // compile error
u.N()
// convert *U to *T and then call M
(*T)(u).M()
}

Golang interface to struct

I have a function that has a parameter with the type interface{}, something like:
func LoadTemplate(templateData interface{}) {
In my case, templateData is a struct, but each time it has a different structure. I used the type "interface{}" because it allows me to send all kind of data.
I'm using this templateData to send the data to the template:
err := tmpl.ExecuteTemplate(w, baseTemplateName, templateData)
But now I want to append some new data and I don't know how to do it because the "interface" type doesn't allow me to add/append anything.
I tried to convert the interface to a struct, but I don't know how to append data to a struct with an unknown structure.
If I use the following function I can see the interface's data:
templateData = appendAssetsToTemplateData(templateData)
func appendAssetsToTemplateData(t interface{}) interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Struct:
fmt.Println("struct")
s := reflect.ValueOf(t)
fmt.Println(s)
//create a new struct based on current interface data
}
return t
}
Any idea how can I append a child to the initial interface parameter (templateData)? Or how can I transform it to a struct or something else in order to append the new child/data?
Adrian is correct. To take it a step further, you can only do anything with interfaces if you know the type that implements that interface. The empty interface, interface{} isn't really an "anything" value like is commonly misunderstood; it is just an interface that is immediately satisfied by all types.
Therefore, you can only get values from it or create a new "interface" with added values by knowing the type satisfying the empty interface before and after the addition.
The closest you can come to doing what you want, given the static typing, is by embedding the before type in the after type, so that everything can still be accessed at the root of the after type. The following illustrates this.
https://play.golang.org/p/JdF7Uevlqp
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
type After struct {
Before
s []string
}
func contrivedAfter(b interface{}) interface{} {
return After{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b).(After)
fmt.Println(a.m)
fmt.Println(a.s)
}
Additionally, since the data you are passing to the template does not require you to specify the type, you could use an anonymous struct to accomplish something very similar.
https://play.golang.org/p/3KUfHULR84
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
func contrivedAfter(b interface{}) interface{} {
return struct{
Before
s []string
}{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b)
fmt.Println(a)
}
You can't append data arbitrarily to a struct; they're statically typed. You can only assign values to the fields defined for that specific struct type. Your best bet is probably to use a map instead of structs for this.
Not recommended, but you can create structs dynamically using the reflect package.
Here is an example:
package main
import (
"encoding/json"
"os"
"reflect"
)
type S struct {
Name string
}
type D struct {
Pants bool
}
func main() {
a := Combine(&S{"Bob"}, &D{true})
json.NewEncoder(os.Stderr).Encode(a)
}
func Combine(v ...interface{}) interface{} {
f := make([]reflect.StructField, len(v))
for i, u := range v {
f[i].Type = reflect.TypeOf(u)
f[i].Anonymous = true
}
r := reflect.New(reflect.StructOf(f)).Elem()
for i, u := range v {
r.Field(i).Set(reflect.ValueOf(u))
}
return r.Addr().Interface()
}
You could use something like the Combine function above to shmush any number of structs together. Unfortunately, from the documentation:
StructOf currently does not generate wrapper methods for embedded fields. This limitation may be lifted in a future version.
So your created struct won't inherit methods from the embedded types. Still, maybe it does what you need.
If you are just looking to convert your interface to struct, use this method.
type Customer struct {
Name string `json:"name"`
}
func main() {
// create a customer, add it to DTO object and marshal it
receivedData := somefunc() //returns interface
//Attempt to unmarshall our customer
receivedCustomer := getCustomerFromDTO(receivedData)
fmt.Println(receivedCustomer)
}
func getCustomerFromDTO(data interface{}) Customer {
m := data.(map[string]interface{})
customer := Customer{}
if name, ok := m["name"].(string); ok {
customer.Name = name
}
return customer
}

Golang method with pointer receiver [duplicate]

This question already has answers here:
X does not implement Y (... method has a pointer receiver)
(4 answers)
Closed 3 years ago.
I have this example code
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i Implementation) GetSomeField() string {
return i.someField
}
func (i Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() IFace {
obj := Implementation{someField: "Hello"}
return obj // <= Offending line
}
func main() {
a := Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
SetSomeField does not work as expected because its receiver is not of pointer type.
If I change the method to a pointer receiver, what I would expect to work, it looks like this:
func (i *Implementation) SetSomeField(newValue string) { ...
Compiling this leads to the following error:
prog.go:26: cannot use obj (type Implementation) as type IFace in return argument:
Implementation does not implement IFace (GetSomeField method has pointer receiver)
How can I have the struct implement the interface and the method SetSomeField change the value of the actual instance without creating a copy?
Here's a hackable snippet:
https://play.golang.org/p/ghW0mk0IuU
I've already seen this question In go (golang), how can you cast an interface pointer into a struct pointer?, but I cannot see how it is related to this example.
Your pointer to the struct should implement the Interface. In that way you can modify its fields.
Look at how I modified your code, to make it working as you expect:
package main
import (
"fmt"
)
type IFace interface {
SetSomeField(newValue string)
GetSomeField() string
}
type Implementation struct {
someField string
}
func (i *Implementation) GetSomeField() string {
return i.someField
}
func (i *Implementation) SetSomeField(newValue string) {
i.someField = newValue
}
func Create() *Implementation {
return &Implementation{someField: "Hello"}
}
func main() {
var a IFace
a = Create()
a.SetSomeField("World")
fmt.Println(a.GetSomeField())
}
The simple answer is that you won't be able to have the struct implement your interface while having SetSomeField work the way you want.
However, a pointer to the struct will implement the interface, so changing your Create method to do return &obj should get things working.
The underlying problem is that your modified SetSomeField method is no longer in the method set of Implementation. While the type *Implementation will inherit the non-pointer receiver methods, the reverse is not true.
The reason for this is related to the way interface variables are specified: the only way to access the dynamic value stored in an interface variable is to copy it. As an example, imagine the following:
var impl Implementation
var iface IFace = &impl
In this case, a call to iface.SetSomeField works because it can copy the pointer to use as the receiver in the method call. If we directly stored a struct in the interface variable, we'd need to create a pointer to that struct to complete the method call. Once such a pointer is made, it is possible to access (and potentially modify) the interface variable's dynamic value without copying it.

Resources