I was wondering if it was possible to not know a function name but call it anyway and get values from it. This lead me to the reflection package and I got pretty close but I’m not sure about the last step - if there is one. Again please forgive me if I am missing something obvious, this is my first attempt at doing anything in Go other than getting it setup.
Of course being a compiled language there is no need to iterate through things to find function names, I know them all, but this is something I want to see if it is possible… I’m playing and learning.
Below is the code. What I would really like to do is in the main line extract the values set in ModuleBoot() <“1.0012”, 23> and SomethingBoot() <“1.0000”, 10> but so far all as I can get is structure information. Perhaps that’s just the way it is but perhaps there is a step or change that can make it go the next step.
Hopefully I copied all the relevant code over correctly so it compiles as is:
// Using: go version go1.9.7 linux/amd64
=======================================
FILE: main.go
=======================================
package main
import (
"fmt"
"reflect"
"playing/modules/core"
)
func main() {
miType := reflect.TypeOf(core.ModuleInfo{})
fmt.Println("")
for i := 0; i < miType.NumMethod(); i++ {
method := miType.Method(i)
fmt.Println(method.Name)
in := make([]reflect.Value, method.Type.NumIn())
in[0] = reflect.ValueOf(core.ModuleInfo{})
//fmt.Println("Params in:", method.Type.NumIn(), "Params out:", method.Type.NumOut())
mi := method.Func.Call(in)
fmt.Println("mi:", mi)
fmt.Println("")
}
}
=======================================
FILE: playing/modules/core/something.go
=======================================
package core
func (mi ModuleInfo) SomethingBoot() ModuleInfo {
mi.Version = "1.0000"
mi.Priority = 10
return mi
}
=======================================
FILE: playing/modules/core/modules.go
=======================================
package core
type ModuleInfo struct {
Version string
Priority int
}
func (mi ModuleInfo) ModuleBoot() ModuleInfo {
mi.Version = "1.0012"
mi.Priority = 23
return mi
}
The output I got from this was:
Started delve with config "Debug"
SomethingBoot
mi: [<core.ModuleInfo Value>]
ModuleBoot
mi: [<core.ModuleInfo Value>]
delve closed with code 0
To get the return value as a ModuleInfo, get the underlying value of the first return value and type assert that interface value to ModuleInfo:
// mi has type core.ModuleInfo
mi := method.Func.Call(in)[0].Interface().(core.ModuleInfo)
Run it on the Playground.
You can cut some of the reflect code by type asserting the method to a function with the correct signature and calling that function directly:
for i := 0; i < miType.NumMethod(); i++ {
method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)
mi := method(core.ModuleInfo{})
fmt.Println("Version", mi.Version)
fmt.Println("Priority", mi.Priority)
fmt.Println("")
}
Run it on the Playground
Go natively supports functions as values; you don't need reflection to do this.
In particular, if you make your two functions top-level functions (not specifically tied to a struct):
package core
type ModuleInfo struct { ... }
func SomethingBoot() ModuleInfo
func ModuleBoot() ModuleInfo
Then you can write a function that takes a function as a parameter:
func PrintVersion(func booter() core.ModuleInfo) {
mi := booter()
fmt.Printf("version %s\n", mi.Version)
}
And you can just pass the pre-existing functions as parameters:
PrintVersion(core.SomethingBoot)
PrintVersion(core.ModuleBoot)
Notice that there aren't parentheses after the function name: you are passing the function itself as a parameter, not calling the function and passing its return value.
Related
This question already has an answer here:
Golang static identifier resolution
(1 answer)
Closed 4 months ago.
How can I determine the type of a variable through static analysis?
Suppose I have the following code:
func doSomething(x interface{}) {}
func main() {
p := Person()
doSomething(p)
}
And I want to analyze doSomething(person), is it possible to get the type of Person through static analysis?
What if there were multiple levels of assignment?
p1 := Person()
p2 := p1
doSomething(p2)
or
parent := Parent()
p := Parent.Child() // type Person
doSomething(p)
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Finding the type of an expression through static analysis is non-trivial, and sometimes not possible, for details see Golang static identifier resolution.
The use case is that I have a generic function that is commonly used throughout the (very large) codebase, and would like to introduce a new type safe version of this function. To do this, I hope to automatically determine the "type" of the function and refactor it accordingly:
// old
DB.InsertRow(person)
// new
Person.InsertRow(person)
Just for refactoring purposes, I don't think it is worth the hassle to implement it.
What you may do is change the signature of DB.InsertRow() temporarily to accept only a specific type such as int or your custom type you're sure is not used anywhere (e.g. type tempFoo struct{}).
To what end? Doing so, the compiler will do the hard work for you. You will see error messages showing exactly the types your codebase is trying to pass to DB.InsertRow(), so I'd say mission accomplished.
For example this code compiles:
func doSomething(x interface{}) {}
func main() {
doSomething(image.Pt(1, 2))
doSomething("abc")
doSomething(image.Rect) // image.Rect is a function which we don't call,
// so we're passing a value of a function type here
}
If we change doSomething():
func doSomething(x int) {}
We get the types we're seeking for from the compiler:
./prog.go:10:14: cannot use image.Pt(1, 2) (value of type image.Point) as type int in argument to doSomething
./prog.go:11:14: cannot use "abc" (untyped string constant) as int value in argument to doSomething
./prog.go:12:14: cannot use image.Rect (value of type func(x0 int, y0 int, x1 int, y1 int) image.Rectangle) as type int in argument to doSomething
Using the advice from Golang static identifier resolution to use golang.org/x/tools/go/types, I found that this was pretty straight forward to do with the golang.org/x/tools/go/analysis package, which has the types info available alongside the parsed ast.
This was my solution:
package rewriter
import (
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
inspect.Nodes(nodeFilter, func(node ast.Node, push bool) bool {
callExpr, ok := node.(*ast.CallExpr)
if !ok {
return true
}
funcExpr, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
// check method name
if funcExpr.Sel.Name != "doSomething" {
return true
}
for _, arg := range callExpr.Args {
// lookup type of the arg
argType := pass.TypesInfo.Types[arg].Type
if argType.String() == "*rewriter.Person" {
// do whatever you want here
}
}
return false
})
return nil, nil
}
One can augment this to look at the receiver of the method and add refactoring logic as needed (using analysis.Diagnostic).
I am passing a pointer to a string, to a method which takes an interface (I have multiple versions of the method, with different receivers, so I am trying to work with empty interfaces, so that I don't end up with a ton of boilerplate madness. Essentially, I want to populate the string with the first value in the slice. I am able to see the value get populated inside the function, but then for some reason, in my application which calls it, tha value doesn't change. I suspect this is some kind of pointer arithmetic problem, but could really use some help!
I have the following interface :
type HeadInterface interface{
Head(interface{})
}
And then I have the following functions :
func Head(slice HeadInterface, result interface{}){
slice.Head(result)
}
func (slice StringSlice) Head(result interface{}){
result = reflect.ValueOf(slice[0])
fmt.Println(result)
}
and... here is my call to the function from an application which calls the mehtod...
func main(){
test := x.StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
x.Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println(result)
}
*NOTE : I am aware that getting the first element doesn't need to be this complicated, and could be slice[0] as a straight assertion, but this is more of an exercise in reusable code, and also in trying to get a grasp of pointers, so please don't point out that solution - I would get much more use out of a solution to my actual problem here * :)
As you said in your NOTE, I'm pretty sure this doesn't have to be this complicated, but to make it work in your context:
package main
import (
"fmt"
"reflect"
)
type HeadInterface interface {
Head(interface{})
}
func Head(slice HeadInterface, result interface{}) {
slice.Head(result)
}
type StringSlice []string
func (slice StringSlice) Head(result interface{}) {
switch result := result.(type) {
case *string:
*result = reflect.ValueOf(slice[0]).String()
fmt.Println("inside Head:", *result)
default:
panic("can't handle this type!")
}
}
func main() {
test := StringSlice{"Phil", "Jessica", "Andrea"}
// empty result string for population within the function
var result string = ""
// Calling the function (it is a call to 'x.Head' because I lazily just called th import 'x')
Head(test, &result)
// I would have thought I would have gotten "Phil" here, but instead, it is still empty, despite the Println in the function, calling it "phil.
fmt.Println("outside:", result)
}
The hard part about working with interface{} is that it's hard to be specific about a type's behavior given that interface{} is the most un-specific type. To modify a variable that you pass as a pointer to a function, you have to use the asterisk (dereference) (for example *result) on the variable in order to change the value it points to, not the pointer itself. But to use the asterisk, you have to know it's actually a pointer (something interface{} doesn't tell you) so that's why I used the type switch to be sure it's a pointer to a string.
The service I'm writing receive code snippets and process them, the snippets could either be complement program or a fragment, if it is a fragment, I need to add the enclosing main function. For example, the snippet:
var v int
v = 3
fmt.Println(v)
should be classified as a fragment, and add main to it:
func main() {
var v int
v = 3
fmt.Println(v)
}
If the snippet is:
package main
import "fmt"
func main() {
fmt.Println("hello")
}
then no modification should be done.
The way I'm doing now is run the go parser against the snippet:
var fset *token.FileSet
file, err := parser.ParseFile(fset, "stdin", code, 0)
if err != nil {
// add function
code = fmt.Sprintf("func main() {\n%s\n}", code)
// ...
}
This works for the 1st snippet above, however it fails if the fragment has a main function after some other declarations, e.g.
type S struct {
a int
}
func main() {
fmt.Println("foo")
}
I also try to look into the file returned by ParseFile, check the Decls, but it looks it will stop parsing after the 1st error, so Decls is nil in this case. So my question is is there a robust way to handle this?
PS. The inclusion of package clause and the required imports are not relevant because I'm feeding the processed code into golang.org/x/tools/imports anyway.
The dumbest thing that might work is after reading in the file (to a buffer most likely), is to do a string search for func main(){.
If it isn't formatted already, you might need to change that to a regex with whitespaces, but it should be pretty straight-forward.
For example, I want to do something like this,
package main
import (
"fmt"
"reflect"
)
func main() {
var f func(int) int
v := reflect.ValueOf(f)
fmt.Println(v.ReturnType() == reflect.TypeOf(1)) // => true
}
ReturnType method doesn't exist in reflect package.
My question is, can I implement such a function without using cgo.
Rather than using reflect.ValueOf(f) try reflect.TypeOf(f). The Type type has two relevant methods named NumOut and Out(int). To get the types of all return values in order, you can use the following loop
typ := reflect.TypeOf(f)
for i := 0; i < typ.NumOut(); i++ {
returnType := typ.Out(i)
// do something with returnType
}
If you're certain your function only has one return value, you can always get it with Out(0), the standard disclaimers about making sure your input is correct apply.
In my Go program, there are configuration values that I want to be constant for the duration of program execution, but that I want to be able to change at the deployment site. As far as I can tell, there's no way to achieve this with the const keyword, since (again, as far as I can tell) its value must be a constant specified at compile time. This means that the only way to achieve what I want would be to declare normal variables and initialize them during the package's init function. It's not that that won't work, but rather that there will now be nothing to prevent these pseudo-constant's values from changing.
My two questions are:
Am I missing something about how const works?
Assuming I'm not, what's the preferred way to handle this? A public function that returns a private variable that I never expose, never changing it? Just hoping people don't alter the variables, since they're really configuration settings?
Create a file "config.go" and create the vars you want to expose.
Don't export them (make them all lower case). Instead create public (upper case) funcs that give access to each item.
package config
var x = 10
func X() int {
return x
}
When you want those variables you simply import ./config and use them in code as follows:
if config.X()
Obviously, you can set the variables in the package init.
The following code is almost the same as the second method of #Christopher, except that it is not a module, it located in the main package.
package main
import (
"os"
)
type Config struct {
debug bool
key string
proxyNumber int
}
func (c *Config) Debug() bool {
return c.debug
}
func (c *Config) Key() string {
return c.key
}
func (c *Config) ProxyNumber() int {
return c.proxyNumber
}
const (
CONFIG_NAME = "config.ini"
)
var config *Config
func init() {
DefaultConfig()
if Exists(CONFIG_NAME) {
//try to save the config file
}else {
//try to load from the config file
}
}
func DefaultConfig() {
config = &Config{debug:true, key:"abcde",
proxyNumber:5,
}
}
//Exist: check the file exist
func Exists(path string) bool {
_, err := os.Stat(path)
if err == nil { return true }
if os.IsNotExist(err) { return false }
return false
}
you can use config to load and save the config file.
This is a very good question because it delves into what I suspect may be an omission from Go - immutable state.
From the language reference, "constant expressions may contain only constant operands and are evaluated at compile-time."
You cannot make vars constant, which is a shame. Joe's answer proposes encapsulation as a solution, which will work well - but it's verbose, tedious and might introduce errors.
By comparison, many impure functional languages combine mutable variables with single-assignment immutable values. For example, Scala has the keywords 'val' and 'var'; the meaning of Scala's 'var' is quite similar to Go's 'var'. Immutability is a useful tool in the toolbox because referentially-transparent side-effect-free functions can be written, alongside stateful mutable procedural code. Both have their place. Immutability is also an valuable tool for concurrency because there is no worry about possible race conditions if immutable values are shared between goroutines.
So in my opinion, amongst its many strengths, this is one of Go's shortcomings. It would presumably not be hard to support vals as well as vars, the difference being that the compiler checks that each val is assigned exactly once.
Until that feature is added, you have encapsulation as your only option.
You can do something like this:
package main
import (
"fmt"
"strconv"
)
var a string
func main() {
myvar, err := strconv.Atoi(a)
if err != nil {
fmt.Println(err)
}
fmt.Println(myvar)
}
and compile the program with
go build -ldflags '-X main.a 10' test.go
That way you can define a constant during compile time.
Just use standard go flags with iniflags. Standard go flags allow setting arbitrary config variables at program start via passing command-line flags, while iniflags "magically" add support for reading config variables from ini files.
You can wrap the variable in a function that returns its value:
func genConst(x int) func() int {
return func() int {
return x
}
}
var Constx = genConst(5)
var x1 = Constx()
This way the value cannot be changed by accident, even in the file where it's defined