how to generate or change code in compile time? - go

I want to add some code to start of function.
like
source code:
func A(){
do something...
}
final code:
func A(){
ADDED CODE
do something...
}
I`m using //go:generate right now,but it will change the source code and should run it every function changed,so I wonder if there any way to do the job in compile time

What about using a function call to add code?
package mypkg
var extra = func() {}
func A() {
extra()
// ...do something
}
Then you can include or exclude an extra file to the same package:
package mypkg
func init() {
extra = func() {
// ADDED CODE
}
}
You even could select from one ore more files with alternatives for the extra() function.

[H]ow to generate or change code in compile time?
You have to modify the compiler. (Don't do that.)

Related

Go - Pass callback function to child (imported) package

I have a go program, MyPackage, and a logging package within this, MyPackage/logs. We have a function func Cleanup(params CleanupParams) written in MyPackage that we want to use as a callback in case of any panic within our log function implemented in MyPackage/logs. This function is already written and being used by MyPackage, so we could all the code across but this would be very messy and involve a lot of copying dependent functions.
The approach I am thinking is this: In MyPackage, we have a function func SetupLogs, and could pass this Cleanup callback function as a parameter. However this ends up being a circular dependency, just since we have reference to a function on MyPackage from our logs package. Is there a way to pass this function, maybe with type any?
package MyPackage
import . "MyPackage/logs"
func main() {
cleanupParams := ...
...
SetupLogs(Cleanup, cleanupParams)
...
}
func Cleanup(params *CleanupParams) {
...
}
And our logs package:
package MyPackage/logs
type LogCallback func(*CleanupParams)
func SetupLogs(callback LogCallback, cleanupParams *CleanupParams) {
...
go LogLoop(callback, cleanupParams)
}
func LogLoop(callback LogCallback, cleanupParams *CleanupParams) {
defer callback(cleanupParams)
for {
// Keep checking if we have been channelled another message to log
// If we are logging and have to Panic() then our callback gets run
}
}
So is there any way to call the parent function from the imported class, since we don't need to know anything about the types of the function or its parameters, we just need to push our program to make sure the method gets called?
Thank you!
Use type func() for the callback function:
func SetupLogs(callback func()) {
...
go LogLoop(callback)
}
func LogLoop(callback func()) {
defer callback()
for {
// Keep checking if we have been channelled another message to log
// If we are logging and have to Panic() then our callback gets run
}
}
Use a closure to create a func() that calls Cleanup with the parameters.
SetupLogs(func() { Cleanup(cleanupParams) })

Export functions from internal package in Go

I'm testing the idea of putting most of my code in an internal package and then picking exactly which of the methods / types from there I'm exposing to the outside world. Code would look like:
/mypackage/internal/catapult
package catapult
func Load(boulder Boulder) {
// ...
}
func Trigger() *Launch {
// ...
}
// ...
Maybe Load is being called by other internal packages (/mypackage/internal/randomevents/boredsoldier and /mypackage/internal/actualattackstrategy) but shouldn't be allowed by users outside of internal. All those are allowed to do is Trigger the catapult once it's loaded.
So now I'd like to have a package above internal (/mypackage/general) where Trigger is exposed but not Load. I was hoping to do something like:
package general
const TriggerCatapult = catapult.Trigger
// ^ does not work because a function cannot be a const
var TriggerCatapult = catapult.Trigger
// ^ technically works but now the value of TriggerCatapult can be overwritten by any package user
func TriggerCatapult() *catapult.Launch {
return catapult.Trigger()
}
// ^ works. It's just "painful" to have to reproduce the entire function's signature every time
Is there a better way to do this?
No, there is no better way to do this that the way you provide:
func TriggerCatapult() *catapult.Launch {
return catapult.Trigger()
}
You shouldn't return unexported types though, and most linters would catch this for you.
If a user is going to interact directly with things in catapult, then that package should not be internal.

Golang flag library: Unable to override Usage function that prints out command line usage

I am working on a simple command line tool and I found the default Usage message a bit lacking. I want to define my own and I think I am doing it right I am referring to this example.
I commented out most of the code I had written so the file containing the main function now looks like this:
package main
import (
"flag"
"fmt"
"os"
)
func main() {
// set the custom Usage function
setupFlags(flag.CommandLine)
// define flags...
// then parse flags
flag.Parse()
// custom code that uses flag values...
}
func setupFlags(f *flag.FlagSet) {
f.Usage = func() {
fmt.Println("foo bar")
}
}
It seems like this should work, but it doesn't. When running <binary> -h I get the default usage message and not my custom foo bar message that I defined in my custom function. I am using Go version 1.3.3 on OSX. I found this commit but it is for Go 1.4rc2.
What am I doing wrong?
Edit:
Actually revisiting your code it works! What version of Go are you using? Maybe you need to rebuild your code.
The decision of what Usage function to call is in the flag.go source file, line 708, unexported function usage() (this is from Go 1.4):
func (f *FlagSet) usage() {
if f.Usage == nil {
if f == CommandLine {
Usage()
} else {
defaultUsage(f)
}
} else {
f.Usage()
}
}
This tells if the FlagSet.Usage is not nil, it will be called. If it is not called for you, it's most likely you're using a Go version prior to 1.4 (which you confirmed in your comment).
But since you're using the default flag.CommandLine flagset, you can simply write:
// Note "flag.Usage" instead of "f.Usage"
flag.Usage = func() {
fmt.Println("foo bar")
}

How to access flags outside of main package?

We parse flags in main.go which is in main package, of course. Then we have another package where we want to read some flag's value.
flags.Args() work fine, it will return all non-flag values.
But I cannot figure out to how read already parsed value for a flag in a package other than main.
Is it possible?
Thanks
Amer
I had the same requirement recently and I wanted a solution that avoided calling flag.Parse repeatedly in init functions.
Perusing the flag package I found Lookup(name string) which returns a Flag which has a Value. Every built in Value implements the flag.Getter interface. The call chain looks like this:
flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
If you mistype the flag name or use the wrong type you get a runtime error. I wrapped the lookup in a function that I call directly where needed since the lookup and get methods are fast and the function is not called often. So the main package declares the flag.
// main.go
package main
import "flag"
var httplog = flag.Bool("httplog", false, "Log every HTTP request and response.")
func main() {
flag.Parse()
// ...
}
And the utility package, which is decoupled from main except for the flag name, reads the flag value.
// httpdiag.go
package utility
import "flag"
func logging() bool {
return flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
}
You can define the var storing the flag in the separate package, as an exported variable, then call the flag parsing in the main package to use that variable, like this:
mypackage/const.go
var (
MyExportedVar string
)
mainpackage/main.go
func init() {
flag.StringVar(&mypackage.MyExportedVar, "flagName", "defaultValue", "usage")
flag.Parse()
}
This way, everybody can access that flag, including that package itself.
Note:
this only works for exported variables.
You can define the flag in that package and call flag.Parse() in func init(), flag.Parse can be called multiple times.
However, if you want to access the flag's value from multiple packages you have to expose it or create an exposed function to check it.
for example:
// pkgA
var A = flag.Bool("a", false, "why a?")
func init() {
flag.Parse()
}
// main package
func main() {
flag.Parse()
if *pkgA.A {
// stuff
}
}
Also you can use FlagSet.Parse(os.Args) if you want to reparse the args.
When you parse your flags, parse them into global variables which start with an initial Capital so they are public, eg
package main
var Species = flag.String("species", "gopher", "the species we are studying")
func main() {
flag.Parse()
}
Then in your other package you can refer to them as
package other
import "/path/to/package/main"
func Whatever() {
fmt.Println(main.Species)
}

How to use other struct methods from other files in Golang

I have a file called login.go and account.go
In login.go
func (api *ApiResource) test() {
fmt.Println("Works!")
}
In account.go I have:
func main () {
Res := new(ApiResource)
Res.test()
}
Buit I'm getting undefined:test error.
They both use package main and are on same src/ folder
What do I need to fix here?
If you used go run then you must pass both files to like go run login.go account.go.

Resources