I'm passing objects of two different structs to a function where it's compared with an existing object saved as interface {} type.
In the following how can I make two objects comparable for Equality ===
In this attempt, comparison with bar works fine but with foo it throws a panic error in spite both objects are of struct type
Go Playground
package main
import "fmt"
type Foo struct {
TestMethod func(str string)
}
type Bar struct {}
type IQux interface {
Compare(object interface{}) bool
}
type Qux struct {
Method func(str string)
Reference interface{}
}
func (qux Qux) Compare(object interface{}) bool {
return object == qux.Reference
}
func testMethod(str string) {
fmt.Println(str)
}
func main() {
foo := Foo{TestMethod:testMethod}
bar := Bar{}
ob := &Qux{Method: foo.TestMethod, Reference: foo}
ob.Compare(bar) // works fine
ob.Compare(foo) // panic: runtime error: comparing uncomparable type main.Foo
}
You have a little typo, just try:
package main
import "fmt"
type Foo struct {
TestMethod func(str string)
}
type Bar struct {}
type IQux interface {
Compare(object interface{}) bool
}
type Qux struct {
Method func(str string)
Reference interface{}
}
func (qux Qux) Compare(object interface{}) bool {
return object == qux.Reference
}
func testMethod(str string) {
fmt.Println(str)
}
func main() {
foo := &Foo{TestMethod:testMethod}
bar := Bar{}
ob := Qux{Method: foo.TestMethod, Reference: foo}
ob.Compare(bar) // works fine
ob.Compare(foo) // panic: runtime error: comparing uncomparable type main.Foo
}
Related
Suppose I have some structs defined in package pkg:
package pkg
type Foo struct {
FieldA string
FieldB string
}
type Bar struct {
FieldA string
FieldB string
}
func (Foo) Show() {
fmt.Println("Foo")
}
func (Bar) Show() {
fmt.Println("Bar")
}
type Showable interface {
Show()
}
Registry := map[string]Showable{
//not sure about value type^
"Foo": Foo, // staticcheck shows: not a type
"Bar": Bar, //
}
And I want to instantiate the structs dynamically; something like this:
package main
import "url/user/pkg"
func main() {
foo := pkg.Registry["Foo"]{
FieldA: "A",
FieldB: "B",
}
bar := pkg.Registry["Bar"]{
FieldA: "X",
FieldB: "Y",
}
foo.Show()
bar.Show()
}
The above clearly doesn't work.
Is it possible to achieve this? I am new to go. I have looked at reflect, I have tried to build the Registry with pointers, pointers of empty instance, but couldn't figure out a way to do this.
Ultimately, I am trying to write a command line utility to change themes of certain programs. I have written program specific methods (like Show in above example), and I am trying to read the program specific params from a config.json file, and create the instances dynamically.
If I correctly understand what you are trying to achieve, here is
the way to do that:
registry.go:
package pkg
import (
"fmt"
"io"
)
type NewShowable func(r io.Reader) Showable
type Showable interface {
Show()
}
type Foo struct {
FieldA string
FieldB string
}
func newFoo(r io.Reader) Showable {
// Read config from r and construct Foo
return Foo{}
}
func (Foo) Show() {
fmt.Println("Foo")
}
type Bar struct {
FieldA string
FieldB string
}
func newBar(r io.Reader) Showable {
// Read config from r and construct Bar
return Bar{}
}
func (Bar) Show() {
fmt.Println("Bar")
}
var Registry = map[string]NewShowable{
"Foo": newFoo,
"Bar": newBar,
}
main.go:
package main
import (
"log"
"os"
"url/user/pkg"
)
func main() {
f, err := os.Open("config.json")
if err != nil {
log.Fatalln(err)
}
defer f.Close()
foo := pkg.Registry["Foo"](f)
f2, err := os.Open("config2.json")
if err != nil {
log.Fatalln(err)
}
defer f2.Close()
bar := pkg.Registry["Bar"](f2)
foo.Show()
bar.Show()
}
I'm playing around with Golang and test cases in it, but it's almost completely different from other testing libraries in other languages (I'm with JS background)
In my file I have:
type MyHandler struct {
myBool bool
Person searchFile.Person
}
And lastly in my third file I have:
type Person interface {
searchFor(name string) (string, error)
}
In my main_test.go I have the following line:
h := &MyHandler{myBool: false} <- how can I mock the searchFor function in Golang
It's just an interface, so simply create a struct that implements the interface (and modify the interface so the method is exported, since it doesn't really make sense to have an unexported method in an interface):
type Person interface {
SearchFor(name string) (string, error)
}
type MockSearcher struct{}
func (m MockSearcher) SearchFor(name string) (string, error) {
return "mock name", nil
}
person := MockSearcher{}
h := &MyHandler{myBool: false, Person: person}
You can embed that interface !
package main
import (
"play.ground/sealed"
)
type sealedStruct struct {
sealed.Interface
}
func (s sealedStruct) sealed() {}
var j sealed.Interface = sealedStruct{}
func main() {
}
-- go.mod --
module play.ground
-- sealed/interface.go --
package sealed
type Interface interface {
sealed()
}
-- sealed/interface_test.go --
package sealed_test
import "test/d/sealed"
type sealedStruct struct {
sealed.Interface
}
func (s sealedStruct) sealed() {}
var j sealed.Interface = sealedStruct{}
https://play.golang.org/p/Ic_TnrLlF_u
I began to learn Go and have trouble understanding the following:
package main
import "fmt"
type I interface {
foo(interface {})
}
type S struct {}
func (s S) foo(i int) {
fmt.Println(i)
}
func main() {
var i I = S{}
i.foo(2)
}
This fails with:
cannot use S literal (type S) as type I in assignment:
S does not implement I (wrong type for foo method)
have foo(int)
want foo(interface {})
I don't understand why Go doesn't accept the foo(int) signature given the fact that int implements interface {}. Can anyone help with an explanation?
I think your understanding of interface isn't sound. Interface{} itself is a type. It consists of two things : underlying type and underlying value.
Golang doesn't have overloading. Golang type system matches by name and requires consistency in the types
So, when you are defining a function taking a interface type as a parameter:
foo(interface {})
This is a different function from a function taking int type:
foo(int)
So you should change the following line to
func (s S) foo(i interface{}) {
fmt.Println(i)
}
Or better yet to this:
type I interface {
foo()
}
type S struct {
I int
}
func (s S) foo() {
fmt.Println(s.I)
}
func main() {
var i I = S{2}
i.foo()
}
The error message itself is self-explaining:
"S does not implement I (wrong type for foo method)"
so S{} which is of S type cannot be used on the RHS of type I variable assignment.
To implement I interface, type S needs to define foo function with the exact same signature.
To achieve what you wanted, you can use empty interface as input parameter for your foo function in S and do type assertion
package main
import "fmt"
type I interface {
foo(interface {})
}
type S struct {}
func (s S) foo(i interface{}) {
if i, ok := i.(int); ok{
fmt.Println(i)
}
}
func main() {
var i I = S{}
i.foo(2)
i.foo("2")
}
Try it in go playground
I want to use some external code that requires a pointer to a struct. At the point that the code is called, I have an interface variable.
When creating a pointer off of that variable, the pointer's type is interface{}* when I need it to be the pointer type of the struct's type.
Image the code in TestCanGetStructPointer does not know about the Cat class, and that it exists in some external package.
How can I cast it to this?
Here is a code sample:
import (
"reflect"
"testing"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func TestCanGetStructPointer(t *testing.T) {
interfaceVariable := somethingForCats.getSomething()
pointer := &interfaceVariable
interfaceVarType := reflect.TypeOf(interfaceVariable)
structPointerType := reflect.PtrTo(interfaceVarType)
pointerType := reflect.TypeOf(pointer)
if pointerType != structPointerType {
t.Errorf("Pointer type was %v but expected %v", pointerType, structPointerType)
}
}
The test fails with:
Pointer type was *interface {} but expected *parameterized.Cat
#dyoo's example does work, but it relies on you to manually cast Dog and Cat.
Here's a bit of a convoluted/verbose example which avoids that constraint somewhat:
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "Fuzzy Wuzzy"}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func main() {
interfaceVariable := somethingForCats.getSomething()
castVar := reflect.ValueOf(interfaceVariable)
castVar.Convert(castVar.Type())
// If you want a pointer, do this:
fmt.Println(reflect.PtrTo(castVar.Type()))
// The deref'd val
if castVar.Type() != reflect.TypeOf(Cat{}) {
fmt.Printf("Type was %v but expected %v\n", castVar, reflect.TypeOf(&Cat{}))
} else {
fmt.Println(castVar.Field(0))
}
}
Playground Link
I found this thread: https://groups.google.com/forum/#!topic/golang-nuts/KB3_Yj3Ny4c
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
//
// Return a pointer to the supplied struct via interface{}
//
func to_struct_ptr(obj interface{}) interface{} {
fmt.Println("obj is a", reflect.TypeOf(obj).Name())
// Create a new instance of the underlying type
vp := reflect.New(reflect.TypeOf(obj))
// Should be a *Cat and Cat respectively
fmt.Println("vp is", vp.Type(), " to a ", vp.Elem().Type())
vp.Elem().Set(reflect.ValueOf(obj))
// NOTE: `vp.Elem().Set(reflect.ValueOf(&obj).Elem())` does not work
// Return a `Cat` pointer to obj -- i.e. &obj.(*Cat)
return vp.Interface()
}
//
// Dump out a pointer ...
//
func test_ptr(ptr interface{}) {
v := reflect.ValueOf(ptr)
fmt.Println("ptr is a", v.Type(), "to a", reflect.Indirect(v).Type())
}
func main() {
cat := Cat{name: "Fuzzy Wuzzy"}
// Reports "*main.Cat"
test_ptr(&cat)
// Get a "*Cat" generically via interface{}
sp := to_struct_ptr(cat)
// *should* report "*main.Cat" also
test_ptr(sp)
fmt.Println("sp is",sp)
}
The following may help: http://play.golang.org/p/XkdzeizPpP
package main
import (
"fmt"
)
type Cat struct {
name string
}
type Dog struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "garfield"}
}
func getSomeDog() interface{} {
return Dog{name: "fido"}
}
var somethings = []SomethingGeneric{
SomethingGeneric{getSomething: getSomeCat},
SomethingGeneric{getSomething: getSomeDog},
}
func main() {
for _, something := range somethings {
interfaceVariable := something.getSomething()
cat, isCat := interfaceVariable.(Cat)
dog, isDog := interfaceVariable.(Dog)
fmt.Printf("cat %v %v\n", cat, isCat)
fmt.Printf("dog %v %v\n", dog, isDog)
}
}
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.