package main
import (
"fmt"
"bufio"
"os"
)
func main() {
fmt.Print("LOADED!\n")
fmt.Print("insert y value here: ")
inputY := bufio.NewScanner(os.Stdin)
inputY.Scan()
inputXfunc()
}
func inputXfunc() {
fmt.Print("insert x value here: ")
inputX := bufio.NewScanner(os.Stdin)
inputX.Scan()
slope()
}
func slope() {
fmt.Println(inputX.Text())
}
Whenever I run this program, it says, that inputX and inputY are unidentified. How do I make this program use variables that are accessible to all of the functions? All I want to do is devide inputY by inputX then print out the result
I'm just putting my comment as an answer... I would recommend against this however you could just declare the variable at package scope. It would look like this;
package main
import (
"fmt"
"bufio"
"os"
)
var inputX io.Scanner
func main() {
fmt.Print("LOADED!\n")
fmt.Print("insert y value here: ")
inputY := bufio.NewScanner(os.Stdin)
inputY.Scan()
inputXfunc()
}
func inputXfunc() {
fmt.Print("insert x value here: ")
inputX = bufio.NewScanner(os.Stdin) // get rid of assignment initilize short hand here
inputX.Scan()
slope()
}
func slope() {
fmt.Println(inputX.Text())
}
However a better choice would be to change your method definitions to accept arguments and pass the values into them as needed. This would like like so;
func slope(inputX bufio.Scanner) {
fmt.Println(inputX.Text())
}
slope(myInputWhichIsOfTypeIOScanner)
You can create an init() function and make use of it in the main.go by using package like godotenv to set os's environment variables:
global.go file
package global
import (
"log"
"os"
"strconv"
"github.com/joho/godotenv"
)
var (
SERVER_HOST string
SERVER_PORT int
)
func InitConfig() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
SERVER_HOST = os.Getenv("SERVER_HOST")
SERVER_PORT, _ = strconv.Atoi(os.Getenv("SERVER_PORT"))
}
main.go file
package main
import(
G "path/to/config"
)
func init() {
G.InitConfig()
}
func main() {
G.Init()
}
You will still have to import "G" package in other packages to use the variables, but I think the best way to tackle global variables in Go (or any other languages) is to make use of environment variables.
Related
I'm having difficulty when trying to get path of imported package. When I print result of os.Getwd() inside imported package, it's showing same path like on main package.
This what I did.
Project structure
lib/lib.go
package lib
import "os"
import "fmt"
func init() {
dir, _ := os.Getwd()
fmt.Println("lib.init() :", dir)
}
func GetPath() {
dir, _ := os.Getwd()
fmt.Println("lib.GetPath() :", dir)
}
main.go
package main
import "os"
import "fmt"
import "test-import/lib"
func main() {
dir, _ := os.Getwd()
fmt.Println("main :", dir)
lib.GetPath()
}
Result
lib.init() : /Users/novalagung/Documents/go/src/test-import
main : /Users/novalagung/Documents/go/src/test-import
lib.GetPath() : /Users/novalagung/Documents/go/src/test-import
The result of os.Getwd() from lib/lib.go is still same path like on main. What I want is the real path of the package which is /Users/novalagung/Documents/go/src/test-import/lib/
What should I do? Is it possible?
If you can get a reference to something in the package, you can use reflect to get the import path.
Here's an example on Play:
package main
import (
"bytes"
"fmt"
"reflect"
)
func main() {
var b bytes.Buffer
fmt.Println(reflect.TypeOf(b).PkgPath())
}
PkgPath() only can retrieve the package path for non-pointer
// If the type was predeclared (string, error) or not defined (*T, struct{},
// []int, or A where A is an alias for a non-defined type), the package path
// will be the empty string.
func packageName(v interface{}) string {
if v == nil {
return ""
}
val := reflect.ValueOf(v)
if val.Kind() == reflect.Ptr {
return val.Elem().Type().PkgPath()
}
return val.Type().PkgPath()
}
I'm going to parse HCL configuration file using this repository.
package main
import (
"fmt"
hclParser "github.com/hashicorp/hcl/hcl/parser"
)
const (
EXAMPLE_CONFIG_STRING = "log_dir = \"/var/log\""
)
func main() {
// parse HCL configuration
if astFile, err := hclParser.Parse([]byte(EXAMPLE_CONFIG_STRING)); err == nil {
fmt.Println(astFile)
} else {
fmt.Println("Parsing failed.")
}
}
How can I parse log_dir in this case?
github.com/hashicorp/hcl/hcl/parser is a low-level package. Use the high-level API instead:
package main
import (
"fmt"
"github.com/hashicorp/hcl"
)
type T struct {
LogDir string `hcl:"log_dir"`
}
func main() {
var t T
err := hcl.Decode(&t, `log_dir = "/var/log"`)
fmt.Println(t.LogDir, err)
}
There is also DecodeObject available if you really want to deal with the AST yourself.
I have a main.go file which has:
// running the router in port 9000
func main() {
router,Global := routers.InitApp()
fmt.println(Global)
router.RunTLS(":9000" , "domain.crt" , "domain.key")
}
In router.InitMap I want to declare a global variable which can be accessed throughout my application anywhere. Is is possible? I tried:
func InitApp() (*gin.Engine,string) {
var Global= "myvalue"
router := gin.New()
return router,Global
}
But I can't access the variable Global even in the same package.
declare a variable at the top level - outside of any functions:
var Global = "myvalue"
func InitApp() (string) {
var Global= "myvalue"
return Global
}
Since the name of the variable starts with an uppercase letter, the variable will be available both in the current package through its name - and in any other package when you import the package defining the variable and qualify it with the package name as in: return packagename.Global.
Here's another illustration (also in the Go playground: https://play.golang.org/p/h2iVjM6Fpk):
package main
import (
"fmt"
)
var greeting = "Hello, world!"
func main() {
fmt.Println(greeting)
}
See also Go Tour: "Variables" https://tour.golang.org/basics/8 and "Exported names" https://tour.golang.org/basics/3.
It is better to use the init function for initialisation of global variables. It also will be processed only once even in multiply includes of this package. https://play.golang.org/p/0PJuXvWRoSr
package main
import (
"fmt"
)
var Global string
func init() {
Global = InitApp()
}
func main() {
fmt.Println(Global)
}
func InitApp() (string) {
return "myvalue"
}
My solution:
define the global variable in other package with Set and Get, similar with class set in python
the good part is that you can set global variables in any package, the bad part is that you can mess up the global variables if you use Set not carefully
https://play.golang.org/p/egApePP7kPq
first define global variable
-- globalvar/globalvar.go --
package globalvar
import "fmt"
var Glbv int
func Set(b int) {
Glbv = b
}
func Get() int {
return Glbv
}
func Pr() {
fmt.Printf("inside globarvar = %v \n", Glbv)
} ```
then you can change the global variable in another package
-- otherpackage/otherpackage.go --
package otherpackage
import (
"fmt"
"play.ground/globalvar"
)
func Bar() {
globalvar.Set(3)
}
func Prtf() {
var cc = globalvar.Get()
fmt.Printf("inside otherpackage globalvar=%v \n", cc)
}
main function
package main
import (
"play.ground/globalvar"
"play.ground/otherpackage"
)
func main() {
globalvar.Pr()
otherpackage.Prtf()
globalvar.Set(2)
globalvar.Pr()
otherpackage.Prtf()
otherpackage.Bar()
globalvar.Pr()
otherpackage.Prtf()
}
here is the result
inside globarvar = 0
inside otherpackage globalvar=0
inside globarvar = 2
inside otherpackage globalvar=2
inside globarvar = 3
inside otherpackage globalvar=3
You can also do it like writing a function to initialise the global variable as:
package main
import (
"fmt"
)
func initialise() string {
CommonVariable = "global_variable"
return CommonVariable
}
var CommonVariable string
func main() {
initialise()
fmt.Println(CommonVariable)
}
If you want to take input from user and then initialise it to global variable, just change the line CommonVariable="myvalue" in initialise() function with "Scanf" statement like this:
func initialise() string {
fmt.Scanln(&CommonVariable)
return CommonVariable
}
I'm trying to learn the basics of Go by tweaking examples as I go along the tutorial located here:
http://tour.golang.org/#9
Here's a small function I wrote that just turns ever character to all caps.
package main
import (
"fmt"
"strings"
)
func capitalize(name string) {
name = strings.ToTitle(name)
return
}
func main() {
test := "Sergio"
fmt.Println(capitalize(test))
}
I'm getting this exception:
prog.go:15: capitalize(test) used as value
Any glaring mistakes?
You are missing the return type for capitalize():
package main
import (
"fmt"
"strings"
)
func capitalize(name string) string {
return strings.ToTitle(name)
}
func main() {
test := "Sergio"
fmt.Println(capitalize(test))
}
Playground
Output:
SERGIO
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()
}