I have a Result interface which represents the minimum state of a result. Now there are different structs which implement the Result interface but also add own methods. One of them is SpecialResult which implemented the basic Value() method but also a special Special() method.
You can see this in the following snippet:
package main
import (
"fmt"
"reflect"
)
type Result interface {
Value() string
}
type SpecialResult struct {
value string
}
func (r *SpecialResult) Value() string {
return r.value
}
func (r *SpecialResult) Special() string {
return "look I am special!!"
}
func main() {
sr := &SpecialResult{
value: "1234",
}
doSomething(sr)
}
func doSomething(r Result) {
switch reflect.TypeOf(r).String() {
case "*main.SpecialResult":
fmt.Printf("%s, %s\n", r.Value(), r.(*SpecialResult).Special())
break
default:
fmt.Printf("%s\n", r.Value())
}
}
Playground
Source
When you read the last lines of code you might feel the same as I do: This looks very weird.
Is there a better way to achieve the shown setup?
Bodo
Use Type Assertions
package main
import (
"fmt"
)
type Result interface {
Value() string
}
type SpecialResult struct {
value string
}
func (r *SpecialResult) Value() string {
return r.value
}
func (r *SpecialResult) Special() string {
return "look I am special!!"
}
func main() {
sr := &SpecialResult{
value: "1234",
}
doSomething(sr)
}
func doSomething(r Result) {
if special, ok := r.(*SpecialResult); ok {
fmt.Printf("%s, %s\n", special.Value(), special.Special())
} else {
fmt.Printf("%s\n", r.Value())
}
}
Playground
Related
For the following code:
package main
import "fmt"
type intFunc func(int) int
var t = func() intFunc {
a := func(b int) int { return b}
return a
}
func main() {
fmt.Println(t()(2))
}
Is there a way to return the pointer to the function instead of the function directly? (something like return &a)?
The playground is here: https://play.golang.org/p/IobCtRjVVX
Yes, as long as you convert the types correctly:
https://play.golang.org/p/3R5pPqr_nW
type intFunc func(int) int
var t = func() *intFunc {
a := intFunc(func(b int) int { return b })
return &a
}
func main() {
fmt.Println((*t())(2))
}
And without the named type:
https://play.golang.org/p/-5fiMBa7e_
var t = func() *func(int) int {
a := func(b int) int { return b }
return &a
}
func main() {
fmt.Println((*t())(2))
}
Accessing other packages:
https://play.golang.org/p/X20RtgpEzqL
package main
import "fmt"
var f = fmt.Println
var p2f = &f
func main() {
(*p2f)("it works")
}
I'm learning Go currently and I made this simple and crude inventory program just to tinker with structs and methods to understand how they work. In the driver file I try to call a method from and item type from the items map of the Cashier type. My method have pointer reciever to use the structs directly instead of making copies. When I run the program I get this error .\driver.go:11: cannot call pointer method on f[0]
.\driver.go:11: cannot take the address of f[0]
Inventory.go:
package inventory
type item struct{
itemName string
amount int
}
type Cashier struct{
items map[int]item
cash int
}
func (c *Cashier) Buy(itemNum int){
item, pass := c.items[itemNum]
if pass{
if item.amount == 1{
delete(c.items, itemNum)
} else{
item.amount--
c.items[itemNum] = item
}
c.cash++
}
}
func (c *Cashier) AddItem(name string, amount int){
if c.items == nil{
c.items = make(map[int]item)
}
temp := item{name, amount}
index := len(c.items)
c.items[index] = temp
}
func (c *Cashier) GetItems() map[int]item{
return c.items;
}
func (i *item) GetName() string{
return i.itemName
}
func (i *item) GetAmount() int{
return i.amount
}
Driver.go:
package main
import "fmt"
import "inventory"
func main() {
x := inventory.Cashier{}
x.AddItem("item1", 13)
f := x.GetItems()
fmt.Println(f[0].GetAmount())
}
The part of the code that really pertains to my problem is the GetAmount function in inventory.go and print statement in the driver.go
A map entry cannot be addressed (as its address might change during map growth/shrink), so you cannot call pointer receiver methods on them.
Detail here: https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/4_pabWnsMp0
As Volker said in his answer - you can't get address of an item in the map. What you should do - is to store pointers to items in your map, instead of storing item values:
package main
import "fmt"
type item struct {
itemName string
amount int
}
type Cashier struct {
items map[int]*item
cash int
}
func (c *Cashier) Buy(itemNum int) {
item, pass := c.items[itemNum]
if pass {
if item.amount == 1 {
delete(c.items, itemNum)
} else {
item.amount--
}
c.cash++
}
}
func (c *Cashier) AddItem(name string, amount int) {
if c.items == nil {
c.items = make(map[int]*item)
}
temp := &item{name, amount}
index := len(c.items)
c.items[index] = temp
}
func (c *Cashier) GetItems() map[int]*item {
return c.items
}
func (i *item) GetName() string {
return i.itemName
}
func (i *item) GetAmount() int {
return i.amount
}
func main() {
x := Cashier{}
x.AddItem("item1", 13)
f := x.GetItems()
fmt.Println(f[0].GetAmount()) // 13
x.Buy(0)
f = x.GetItems()
fmt.Println(f[0].GetAmount()) // 12
}
http://play.golang.org/p/HkIg668fjN
While the other answers are useful, I think in this case it is best just to make non-mutating functions not take a pointer:
func (i item) GetName() string{
return i.itemName
}
func (i item) GetAmount() int{
return i.amount
}
I'm trying to retrieve the string value from a reflect.Value,
I expect value.String() to be okok but I got <interface {} Value> instead.
Did I miss something?
package main
import (
"fmt"
"reflect"
)
func dump(args *[]interface{}) {
value := reflect.ValueOf(*args).Index(0)
fmt.Println(value.String())
if value.String() != "okok" {
fmt.Println("miss")
}
}
func main () {
var args []interface{}
args = append(args, "okok")
dump(&args)
}
The documentation for Value.String explains the behavior:
Unlike the other getters, it does not panic if v's Kind is not String.
Instead, it returns a string of the form "<T value>" where T is v's
type.
String is just an implementation of the fmt.Stringer interface.
If you want the value itself, you can use the Interface function on reflect.Value and then do a type assertion to get the string. Example:
package main
import (
"fmt"
"reflect"
)
func dump(args *[]interface{}) {
value := reflect.ValueOf(*args).Index(0)
str := value.Interface().(string)
fmt.Println(str)
if str != "okok" {
fmt.Println("miss")
}
}
func main() {
var args []interface{}
args = append(args, "okok")
dump(&args)
}
Playground link
How I can check that some variable in golang has type func, like this:
func A() {}
func main() {
variable := A
isFunc := IsFunc(variable) // true or false
}
func IsFunc(v interface{}) bool {
return reflect.TypeOf(v).Kind() == reflect.Func
}
Already solved with this:
func IsFunc(fn interface{}) bool {
return reflect.TypeOf(fn).Kind() == reflect.Func
}
I have a function that is being generated using reflection and reflect.MakeFunc, so I don't actually have the return type until runtime.
Inside the template function that MakeFunc is using, is there a way to determine the return type of the concrete function being templated?
Essentially, is there a way to determine the return type iof the currently executing function at runtime?
I know about the Out method:
fn.Type().Out(0)
And I can find the return type of a function easily enough?
But is there a way to find the return type of the currently executing function (as opposed to an explicit passed function reference).
You should check fn.Type().Out(0).Kind(), for example:
func main() {
fnTmpl := func(in []reflect.Value) []reflect.Value {
return []reflect.Value{in[0]}
}
makeFn := func(fptr interface{}) {
fn := reflect.ValueOf(fptr).Elem()
fn.Set(reflect.MakeFunc(fn.Type(), fnTmpl))
}
var nFn func(int) int
makeFn(&nFn)
kind := reflect.TypeOf(nFn).Out(0).Kind()
switch kind {
case reflect.Int:
fmt.Println("int")
}
}
In the case you are talking about, the return type of the currently executing function is always []reflect.Type (because that is what a function passed to reflect.MakeFunc must return). What you really want is the return type of the reflect.makeFuncStub function that called your function.
There is no way to get that (except perhaps some strange inspection of the call stack), but you can make an enhanced version of MakeFunc that provides the information:
package main
import (
"fmt"
"reflect"
)
// MakeFunc is like reflect.MakeFunc, but fn has an extra argument, retType, which
// is passed the desired return type.
func MakeFunc(typ reflect.Type, fn func(args []reflect.Value, retType reflect.Type) (results []reflect.Value)) reflect.Value {
if n := typ.NumOut(); n != 1 {
panic("wrong number of return values")
}
rt := typ.Out(0)
return reflect.MakeFunc(typ, func(args []reflect.Value) (results []reflect.Value) {
return fn(args, rt)
})
}
func makeReturnOne(fptr interface{}) {
fn := reflect.ValueOf(fptr).Elem()
fn.Set(MakeFunc(fn.Type(), returnOne))
}
func returnOne(args []reflect.Value, retType reflect.Type) []reflect.Value {
ret := reflect.New(retType).Elem()
switch retType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
ret.SetInt(1)
case reflect.Float32, reflect.Float64:
ret.SetFloat(1.0)
default:
panic("returnOne only supports int and float types")
}
r := ret.Interface()
fmt.Printf("returning %v as %T\n", r, r)
return []reflect.Value{ret}
}
func main() {
var r1f func() float64
var r1i func() int
makeReturnOne(&r1f)
makeReturnOne(&r1i)
fmt.Println(r1f())
fmt.Println(r1i())
}
I might have misinterpreted what you are trying to achieve, but why not just take the kind of the value you are returning? Modifying OneOfOne's example as follows:
fnTmpl := func(in []reflect.Value) (res []reflect.Value) {
res = []reflect.Value{in[0]}
fmt.Println("Returned:", res[0].Kind())
return res
}
Playground: http://play.golang.org/p/EujmxyGRrI