GO: find/scan for structs/functions - go

Is it possible in GO to find structs or functions by criteria such as name, tag or interface? i.e something along the lines of command line tasks/verbs? i.e:
func cmd1() {
...
}
func cmd2() {
...
}
...
func cmdN() {
}
func main() {
// Inspect os.Args and call cmd{X}() based on args.
...
}
I don't mind what the exact mechanism is and if the final targets are functions or structs - the goal is to get something working by convention without any boilerplate code.

You could use reflection
package main
import (
"flag"
"fmt"
"reflect"
)
var cmd command
type command struct{}
func (c command) execute(name string) {
v := reflect.ValueOf(c)
cmd := v.MethodByName(name)
if !cmd.IsValid() {
fmt.Println(name + " not a command")
return
}
cmd.Call([]reflect.Value{})
}
func (c command) Cmd1() {
fmt.Println("command 1")
}
func (c command) Cmd2() {
fmt.Println("command 2")
}
func (c command) Cmd3() {
fmt.Println("command 3")
}
func main() {
flag.Parse()
cmd.execute(flag.Arg(0))
}
or you could use a map.
package main
import (
"flag"
"fmt"
)
func cmd1() {
fmt.Println("command 1")
}
func cmd2() {
fmt.Println("command 2")
}
func cmd3() {
fmt.Println("command 3")
}
var funcs = map[string]func(){
"cmd1": cmd1,
"cmd2": cmd2,
"cmd3": cmd3,
}
func main() {
flag.Parse()
if f, ok := funcs[flag.Arg(0)]; ok {
f()
} else {
fmt.Println(flag.Arg(0) + " command not found")
}
}

I used a similar approach in "How to test a collection of functions by reflection in Go?"
The idea is to list and find all the functions needed, in my case, functions for a certain struct type:
stype := reflect.ValueOf(s)
for _, fname := range funcNames {
sfunc := stype.MethodByName(fname)
// no parameter => empty slice of Value
ret := sfunc.Call([]reflect.Value{})

Related

Passing for loop values as function parameters

It says: (no value) used as value, but I'm passing loop values from a slice to it!
package main
import "fmt"
func greet(n string) {
fmt.Printf("Hi, %v\n", n)
}
func cycle(n []string, f func(string)) {
for i := 0; i < len(n); i++ {
fmt.Println(f(n[i]))
}
}
func main() {
cycle([]string{"John", "Marie"}, greet)
}
Code snippet on Go Playground
I found the solution: I should have called the function directly, not inside Println().
package main
import "fmt"
func greet(n string) {
fmt.Printf("Hi, %v\n", n)
}
func cycle(n []string, f func(string)) {
for i := 0; i < len(n); i++ {
f(n[i])
}
}
func main() {
cycle([]string{"John", "Marie"}, greet)
}

Override receiver type in test and dependency-inject into logic

Using Go v1.14.3, I'm trying to do the following:
package main
import (
"os"
"github.com/mihaigalos/go-bar/bar"
)
var progressBar bar.Bar
func (*ProgressHandler) New(begin int, end int) {
progressBar.New(begin, end)
}
func main() {
var progressHandler ProgressHandler
send(&progressHandler)
}
So far so good. But when I test, I have no need to see any progressbar, hence my ProgressHandler can be empty, and I want to dependency-inject this object into send().
Inside it will call my specified New().
package main
import (
"testing"
)
func (*ProgressHandler) New(int, int) {
}
func TestSendWorks_whenTypical(t *testing.T) {
expected := true
var progressHandler ProgressHandler
actual := send(&progressHandler)
if actual != expected {
t.Errorf("No Match: %b != %b", actual, expected)
}
}
When I compile this, I get a name collision with the handlers defined in main:
integration_typical_test.go:23:25: (*ProgressHandler).New redeclared in this block
previous declaration at main.go:15:6
I've tried changing the name of the package to something different. The same error there.
How can I improve here?
Use an interface.
type ProgressBar interface {
New(int, int)
}
var progressBar bar.Bar
// New implements ProgressBar
func (*ProgressHandler) New(begin int, end int) {
progressBar.New(begin, end)
}
// change *ProgressHandler to ProgressBar
func send(pb ProgressBar) {
// ...
}
func main() {
var progressHandler ProgressHandler
send(&progressHandler)
}
package main
import (
"testing"
)
type fakeProgressHandler struct{}
func (*fakeProgressHandler) New(int, int) {
}
func TestSendWorks_whenTypical(t *testing.T) {
expected := true
var progressHandler fakeProgressHandler
actual := send(&progressHandler)
if actual != expected {
t.Errorf("No Match: %b != %b", actual, expected)
}
}
Handle nil receiver in the handler.
package main
import (
"os"
"github.com/mihaigalos/go-bar/bar"
)
var progressBar bar.Bar
func (h *ProgressHandler) New(begin int, end int) {
if h == nil {
return
}
progressBar.New(begin, end)
}
func main() {
var progressHandler ProgressHandler
send(&progressHandler)
}
package main
import (
"testing"
)
func TestSendWorks_whenTypical(t *testing.T) {
expected := true
actual := send(nil)
if actual != expected {
t.Errorf("No Match: %b != %b", actual, expected)
}
}

How do you create a slice of functions with different signatures?

How do you create a slice of functions with different signatures? I tried the code below but its feels hack-ish. Do we just bite the bullet and use a slice interface{}?
package main
import (
"fmt"
)
type OneParams func(string) string
type TwoParams func(string, string) string
type ThreeParams func(string, string, string) string
func (o OneParams) Union() string {
return "Single string"
}
func (t TwoParams) Union() string {
return "Double string"
}
func (t ThreeParams) Union() string {
return "Triple string"
}
type Functions interface {
Union() string
}
func Single(str string) string {
return str
}
func Double(str1 string, str2 string) string {
return str1 + " " + str2
}
func Triple(str1 string, str2 string, str3 string) string {
return str1 + " " + str2 + " " + str3
}
func main() {
fmt.Println("Slice Of Functions Program!\n\n")
fSlice := []Functions{
OneParams(Single),
TwoParams(Double),
ThreeParams(Triple),
}
for _, value := range fSlice {
switch t := value.(type) {
case OneParams:
fmt.Printf("One: %s\n", t("one"))
case TwoParams:
fmt.Printf("Two: %s\n", t("one", "two"))
case ThreeParams:
fmt.Printf("Three: %s\n", t("one", "two", "three"))
default:
fmt.Println("Huh! What's that?")
}
}
fmt.Println("\n\n")
}
Is this just a case of trying to do too much with Go?
Please check it, I don't know if it what you want. Because I don't know what are you exactly want.
package main
import (
"fmt"
"reflect"
)
func A() {
fmt.Println("A")
}
func B(A int) {
fmt.Println("B", A)
}
func C(A string, B float32) {
fmt.Println("C", A, B)
}
func main() {
f := []interface{}{A, B, C}
f[0].(func())()
f[1].(func(int))(15)
f[2].(func(string, float32))("TEST", 90)
fmt.Println("\n******* another thing ******")
for a, v := range f {
v := reflect.TypeOf(v)
fmt.Println("#######", a)
fmt.Println("num param :", v.NumIn())
for i := 0; i < v.NumIn(); i++ {
fmt.Println("param :", i, "type is ", v.In(i))
}
}
}
Check on Go Playground
Here I have another example calling using reflect
package main
import (
"fmt"
"reflect"
)
func A() {
fmt.Println("A")
}
func B(A int) {
fmt.Println("B", A)
}
func C(A string, B float32) {
fmt.Println("C", A, B)
}
func main() {
f := []interface{}{A, B, C}
f[0].(func())()
f[1].(func(int))(15)
f[2].(func(string, float32))("TEST", 90)
fmt.Println("\n******* calling with reflect ******")
for a, v := range f {
v := reflect.TypeOf(v)
//calling the function from reflect
val := reflect.ValueOf(f[a])
params := make([]reflect.Value, v.NumIn())
if v.NumIn() == 1 {
params[0] = reflect.ValueOf(1564)
} else if v.NumIn() == 2 {
params[0] = reflect.ValueOf("Test FROM reflect")
params[1] = reflect.ValueOf(float32(123456))
}
val.Call(params)
}
}
Check on Go Playground
depends on what the different you need. upon your example, we could use variadic.
package main
import(
"fmt"
"strings"
)
func foo(ss ...string) string{
return strings.Join(ss, " ")
}
func main(){
fmt.Println(foo("one"))
fmt.Println(foo("one", "two"))
fmt.Println(foo("one", "two", "three"))
}

Is it possible get information about caller function in Golang?

Is it possible get information about caller function in Golang? For example if I have
func foo() {
//Do something
}
func main() {
foo()
}
How can I get that foo has been called from main?
I'm able to this in other language (for example in C# I just need to use CallerMemberName class attribute)
You can use runtime.Caller for easily retrieving information about the caller:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
Example #1: Print caller file name and line number: https://play.golang.org/p/cdO4Z4ApHS
package main
import (
"fmt"
"runtime"
)
func foo() {
_, file, no, ok := runtime.Caller(1)
if ok {
fmt.Printf("called from %s#%d\n", file, no)
}
}
func main() {
foo()
}
Example #2: Get more information with runtime.FuncForPC: https://play.golang.org/p/y8mpQq2mAv
package main
import (
"fmt"
"runtime"
)
func foo() {
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
fmt.Printf("called from %s\n", details.Name())
}
}
func main() {
foo()
}
expanding on my comment, here's some code that returns the current func's caller
import(
"fmt"
"runtime"
)
func getFrame(skipFrames int) runtime.Frame {
// We need the frame at index skipFrames+2, since we never want runtime.Callers and getFrame
targetFrameIndex := skipFrames + 2
// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need
programCounters := make([]uintptr, targetFrameIndex+2)
n := runtime.Callers(0, programCounters)
frame := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(programCounters[:n])
for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
var frameCandidate runtime.Frame
frameCandidate, more = frames.Next()
if frameIndex == targetFrameIndex {
frame = frameCandidate
}
}
}
return frame
}
// MyCaller returns the caller of the function that called it :)
func MyCaller() string {
// Skip GetCallerFunctionName and the function to get the caller of
return getFrame(2).Function
}
// foo calls MyCaller
func foo() {
fmt.Println(MyCaller())
}
// bar is what we want to see in the output - it is our "caller"
func bar() {
foo()
}
func main(){
bar()
}
For more examples: https://play.golang.org/p/cv-SpkvexuM

How to get the name of a function in Go?

Given a function, is it possible to get its name? Say:
func foo() {
}
func GetFunctionName(i interface{}) string {
// ...
}
func main() {
// Will print "name: foo"
fmt.Println("name:", GetFunctionName(foo))
}
I was told that runtime.FuncForPC would help, but I failed to understand how to use it.
I found a solution:
package main
import (
"fmt"
"reflect"
"runtime"
)
func foo() {
}
func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
func main() {
// This will print "name: main.foo"
fmt.Println("name:", GetFunctionName(foo))
}
Not exactly what you want, because it logs the filename and the line number, but here is how I do it in my Tideland Common Go Library (http://tideland-cgl.googlecode.com/) using the "runtime" package:
// Debug prints a debug information to the log with file and line.
func Debug(format string, a ...interface{}) {
_, file, line, _ := runtime.Caller(1)
info := fmt.Sprintf(format, a...)
log.Printf("[cgl] debug %s:%d %v", file, line, info)
I found a better solution, in this function down here you just simply pass a function and the output is gonna be simple and straight.
package main
import (
"reflect"
"runtime"
"strings"
)
func GetFunctionName(temp interface{}) string {
strs := strings.Split((runtime.FuncForPC(reflect.ValueOf(temp).Pointer()).Name()), ".")
return strs[len(strs)-1]
}
And this is an example of how you use this:
package main
import "fmt"
func main() {
fmt.Println(GetFunctionName(main))
}
And this is the answer you should expect:
main
By getting the function name of the previous caller:
import (
"os"
"runtime"
)
func currentFunction() string {
counter, _, _, success := runtime.Caller(1)
if !success {
println("functionName: runtime.Caller: failed")
os.Exit(1)
}
return runtime.FuncForPC(counter).Name()
}

Resources