I have a Character interface defined like:
type Character interface {
SomeFunction()
}
And a Player struct defined like:
type Player struct{}
func (r *Player) SomeFunction() { }
// Some fields and other functions....
Suppose I have a function defined as
func TakeInterface(characterValue Character) {
// Do something
}
The catch is, I want to pass in characterValue as a Player by address so that changes made to it will be made to the Player the caller passed in. In Java and C++, this is easy, but I can't seem to figure it out in Golang. I've tried something like,
func TakeInterface(characterValue &Character) {
// Do something that changes characterValue
}
and then passing in a Player pointer, but then I get the error *Character.Character is pointer to interface, not interface when I try to pass in an address.
How do I go about passing a Player by address to a function that takes a Character/Character pointer? I've been looking around but with no success. Thanks!
Have you tested your code? I'm guessing no, because it works the way you expect it to work. Just pass a pointer to a player when calling the function.
func main() {
p := new(Player)
TakeInterface(p)
}
Or
func main() {
p := Player{0}
TakeInterface(&p)
}
In go you can use a type or a pointer to a type as an argument to a function that takes an interface because both satisfy the interface. You can do both:
var p1 Player
p1.SomeFunction()
var p2 *Player
p2.SomeFunction()
You should do the tour of go: https://tour.golang.org/methods/10
Here is the whole code: https://play.golang.org/p/iQIChLCziG
Related
I am having difficulty writing tests for this 3rd party library I am importing. I think this is because I want my CustomClient struct to have a client interface instead of the *banker.Client. This is making testing very difficult because it's hard to mock a *banker.Client. Any ideas how I can correctly turn this into an interface? So I can easily write mock tests against it and set up a fake client?
type CustomClient struct {
client *banker.Client //I want to change this to an interface
name string
address string
}
func (c *CustomClient) SetHttpClient(httpClient *banker.Client) { //I want to accept an interface so I can easily mock this.
c.client = httpClient
}
The problem is that banker.Client is a third party client I am importing with many structs and other fields inside of it. It looks like this:
type Client struct {
*restclient.Client
Monitor *Monitors
Pricing *Pricing
Verifications *Verifications
}
The end result is that my code looks like this:
func (c *CustomClient) RequestMoney() {
_, err := v.client.Verifications.GetMoney("fakeIDhere")
}
Given methods over fields on the struct, it sure wouldn't be a simple solution. However, we can try to minimize the lengthy test cases on the current package.
Add another layer (package) between your working package and banker. Simplifying the code in example to explain.
Let's say your banker package has the following code:
type Client struct {
Verification *Verification
}
type Verification struct{}
func (v Verification) GetMoney(s string) (int, error) {
...
}
Create another package that imports the banker and has interface defined, say bankops package:
type Bank struct {
BankClient *banker.Client
}
type Manager interface {
GetMoney(s string) (int, error)
}
func (b *Bank) GetMoney(s string) (int, error) {
return b.BankClient.Verification.GetMoney(s)
}
Note: The actual issue (test without interface) is still here in bankops package, but this is easier to test as we are only forwarding the result. Serves the purpose of unit tests.
Finally, in the current package (for me, it is main package), we can
type CustomClient struct {
client bankops.Manager
}
func (c *CustomClient) RequestMoney() {
_, err := c.client.GetMoney("fakeIDhere")
...
}
func main() {
client := &CustomClient{
client: &bankops.Bank{
BankClient: &banker.Client{
Verification: &banker.Verification{},
},
},
}
client.RequestMoney()
}
For working example, check in Playground.
You may add the setters or builders pattern as you were doing in your original code snippet to make the fields (like BankerClient) unexported.
I think it is impossible to make it into interface directly
because we should use the member variables of the Client.
How about making its member into interface?
For example,
for _, test := []struct{}{
testVerification VerificationInterface
}{{
testVerification: v.Client.Verifications
},{
testVerification: VerficationMock
}}{
// test code here
}
In the following example, I'd like to call the setvalue() of the b object via an interface procedure.
I'd like to use an interface because I need to insert different kinds of objects in a list, possibly very big, each obeying a common interface.
However the compiler complains with the following error :
./tests.go:27:6: cannot use newbox(3) (type box) as type container in assignment:
box does not implement container (setValue method has pointer receiver)
Probably I have to define the interface differently, but how?
I know I could transform the setvalue procedure in a function, returning the updated box, but since the object can be very large, and he procedure will be called several times, i'd like to pass the object via a pointer.
Really isn't there a way to define an interface method that receive the calling structure via a pointer?
package main
import "fmt"
type container interface {
setValue (val int)
}
//--------------------------------------
// box is a kind of container
type box struct {
value int
}
func newbox (x int) box {
return box {x}
}
func (cnt *box) setValue(val int) {
(*cnt).value = val
}
// -----------------------------------------------
func main() {
var b container = newbox(3) // HERE IS THE ERROR
fmt.Printf("%v\n",b)
b.setValue(5)
fmt.Printf("%v\n",b)
}
I am using gorm package (https://github.com/jinzhu/gorm) as my database library in golang. I have many classes (database tables) like "Hotel" or "Package". Duplicating code is not good programming practice. As a silly example - lets assume I want to get first object from each table. I can write this method (GetFirstHotel, GetFirstPackage...) for each object. But better way would be to have just a single method GetFirstItem, where I would use first param to create object with same class as parameter, then pass it to gorm, which will fill it with data from database, then return it as interface{}. I tried to use reflect for that, but failed, because I probably don't understand it much.
Maybe I just didn't discover some function in gorm library, or I can't use reflect package properly. How should I implement GetFirstItem function. Is it possible to have this implemented, or should I rather repeat my code?
package main
import (
"github.com/jinzhu/gorm"
)
var db gorm.DB
type Hotel struct {
ID int64
Name string
Lat float64
Lon float64
}
type Package struct {
ID int64
Name string
Text string
}
func GetFirstHotel() (hotel Hotel) {
db.First(&hotel)
}
func GetFirstPackage() (pack Package) {
db.First(&pack)
}
func main() {
var firstHotel, firstPackage interface{}
//first method
firstHotel = GetFirstHotel()
firstPackage = GetFirstPackage()
//method i want to use
firstHotel = GetFirstItem(Hotel{})
firstPackage = GetFirstItem(Package{})
}
func GetFirstItem(item interface{}) interface{} {
//how to implement this?
//probably with some use of reflect package
}
The db.First method returns db reference and hydrates the row into the passed structure.
The closest to your desired method is
func GetFirstItem(item interface{}) error {
return db.First(item).Error
}
This simply requires you keep a reference to the parameter
var firstHotel &Hotel{}
err := GetFirstItem(firstHotel)
Returning the hydrated object for all types would required type parameters (generics). I think you'll find the current situation is workable within limits.
see also: Why no generics in Go?
Given the following example, is it anyhow possible to create a function that can literally reproduce (not only get the reflect.Type) the actual type for further manipulation? I know go is statically typed and although it's very cool that I can pass any struct to a function that defines an interface parameter, is there any chance I can do more the other way around?
I already looked into the reflect package but only found stuff that returned a reflect.Type or reflect.Value. I used the New() method which returned a new reflect.Value - and there I couldn't set any fields. Maybe someone experienced with the reflect package can tell me if this is definitely possible or not - or if there's another way to do it.
package main
import "fmt"
type User struct {
Name string
}
func main() {
user := User{Name:"FooBar"}
DoSomethingGenericWithStruct(user)
}
func DoSomethingGenericWithStruct(i interface{}) {
// access fields of i ...
// or create slice of type of i ([]User) ...
// or instantiate new object of type of i (new User) ...
// ...
}
You would have to pass a pointer to your struct to be able to modify it.
Also keep in mind that using reflection has a high runtime performance cost.
func DoSomethingGenericWithStruct(i interface{}) {
val := reflect.ValueOf(i)
if val.Kind() != reflect.Ptr {
panic("need a pointer")
}
val = val.Elem() // now you can modify it
// add error checking and such, this will panic if it's not a struct or there's no "Name" field
val.FieldByName("Name").SetString("stuff")
}
playground
To create a new element and assign it:
val = val.Elem()
nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
nval.FieldByName("Name").SetString("stuff")
val.Set(nval)
to modify the actual struct, not reflect.Value, you will have to get the interface{} to it then assert it to your type, for example:
nval := reflect.New(val.Type()).Elem() // create a new struct of the same type
user := nval.Interface().(User)
user.Name = "Stuff"
val.Set(reflect.ValueOf(user))
The below does not work obviously:
Arbitrary := struct {
field1 string
field2 string
}{"a", "b"}
fmap := make(map[string]func(string) string)
fmap["fone"] = func(s string) string { fmt.Printf("function fone: %s", s) }
fmap["ftwo"] = func(s string) string { fmt.Printf("function ftwo: %s", s) }
// probably ok, as simple examples go, to this point where reflection needs to be used
// the below does not work
Arbitrary.fone = fmap["fone"]
Arbitrary.fone("hello")
The above is the core of what I'm trying to do: create a struct with values, and then create methods on the struct from a map of functions, or functions passed in. Basically I have a structure with data & ambiguous behavior that needs to be extended with methods unknown until creating the type.
I'm looking for the obvious & inevitable:
How to do this in Go
Why this shouldn't be done, or can't be done in Go (its possible with the reflect package, I just haven't found examples or reasoned thorough it yet)
How this should be done in Go (some sort of interface construct I've not figured out wholly. I've tried an interface which can handle the behavior; but it doesn't account for other behaviors that might be added, at the least I haven't figured out interface usage fully yet which is part of the issue)
If you're a person needing complexity here is the start of the actual task I'm trying to accomplish, making that structs behavior extendable.
I completely misunderstood the question.
NO, you can't create a new struct out of thin air and assign fields to it, also even if you could, for the love of everything that's holy, don't do that.
You can use multiple interfaces for example:
type Base interface {
Id() int //all structs must implement this
}
type Foo interface {
Base
Foo()
}
type Bar interface {
Base
Bar()
}
then make a map[string]Base, and you can assert the value later.
//leaving the original answer as a different approach to the problem.
While usually that kind of stuff is done using reflection, if you have a limited number of accepted "callbacks" you can use type assertion and an interface{} map, dropping the need for reflection.
var ctx = &Ctx{"Hello"}
var funcs = map[string]interface{}{
"m3": ctx.Do,
"m4": func(c *Ctx) { fmt.Println("ctx:", c) },
}
type Ctx struct {
Name string
}
func (c *Ctx) Do() {
fmt.Printf("Do: %+v\n", c)
}
func call(m string) {
if f, ok := funcs[m]; ok {
switch fn := f.(type) {
case func():
fn()
case func(*Ctx):
fn(&Ctx{"Hello world"})
default:
panic(fn)
}
}
}
playground