How to override variables from nested packages in go language? - go

How do I override variables in go from package ?
For example:
file1.go
package A
import "A/B"
var Arg1 = "Hello"
file2.go
package A/B
var Arg1 = "World"
How can I override arg1 in file1.go if arg1 exist in file2.go?

I'm not sure what you mean by "overriding" in this case. (Also let me assume file1.go is 'package a' and file2.go is 'package b')
If you mean to access Arg1, defined in package "b" inside/from within package "a", then eg.:
// In package "a"
x = Arg1 // references a.Arg1
y = b.Arg1 // references b.Arg1
However, nothing resembling overriding happens here. In package "a" both a's Arg1 and b's Arg1 are accessible as different entities; the later via a mandatory qualifier 'b'.

Are you trying to do something like this, where, for example, a specific location (USA), if present, overrides a general location (World)?
// file A/B.go
package B
var location = "USA"
func Location() string {
return location
}
// file A.go
package A
import "A/B"
var location = "World"
func Location() string {
loc := B.Location()
if len(loc) == 0 {
loc = location
}
return loc
}
// file main.go
package main
import (
"A"
"fmt"
)
func main() {
fmt.Println("Hello,", A.Location())
}
Output:
Hello, USA
If not, please provide a better and specific example of what you are trying to do.

You can't. Packages are self-contained.
If package A doesn't export arg1 (lowercase)
it is not visible -- and thus not set-able --
for an other package B.
BTW: "package A/B" looks pretty strange to me.

You could probably do it using a build flag :
go build -ldflags="-X 'package_path.variable_name=new_value'"
Couple of things to be aware of though :
In order to use ldflags, the value you want to change must exist and be a package level variable of type string. This variable can be either exported or unexported. The value cannot be a const or have its value set by the result of a function call
You'll find all the information needed in this excellent post from DO team

Related

Go package Global Variable usage within imports

I am creating a package that will be called from other services that I have in Go. If a service imports this package, and this package has global variables, will the component store the global variables in its' own memory?
So if my package looks something like this,
var global1 = ""
var global2 = ""
var global3 = ""
var global4 = ""
func setAllGlobalValues() error {
// some logic that checks if globals are nil
// if not setting it to a value after some computation.
// returns nil or an actual error.
}
func DoesSomethingUsingGlobalVars() (bool, error) {
// sets and uses the global vars.
// Does some sort of computation and returns a bool, nil or nil,error
}
Then in the service I would import this package and use the doesSomethingUsingGlobalVars function.
Will the component using this package store the global variables in its own memory? I can't really test it now with my services with the way things are set up so I'm just curious if anyone knows.
Essentially, will this work or will the global vars be nil each and every-time anything is called from a service that imports this package?
Thanks in advance all!
When your program imports this package, the globals will be set when you call SetAllGlobalValues(), and later, when you call DoesSomethingUsingGlobalVars(), those values will already be set. Note that the first letter of those function names must be capitalized so that they are exported and available for use by other packages. If the variables are not exported, as shown in your code snippet, you will not be able to access them directly from the caller.
It seems as if you are trying to reinvent objects. Instead of your code, do
something like this:
package some
import "fmt"
type Thing struct {
One string
Two string
Three string
Four string
}
func NewThing() Thing {
return Thing{"One", "Two", "Three", "Four"}
}
func (t Thing) Print() {
fmt.Println(t.One, t.Two, t.Three, t.Four)
}
Then, the "global variables" are only calculated once, when you call NewThing.

How to resolve `import cycle not allowed` while loading model from separate folder

I'm going to modularize my project, but I have some problems.
Normally, I will put all model files into the same package models (same folder, about 30 files), but now I want to put them into separate folders to manage them easier (each module will have their own model folder).
But if I try to put the model in separate folders like in this image, I will get "import cycle error" because they are not the same package (two tables will be used to lookup each other, this is where error happens).
https://i.imgur.com/3wqJ4BK.png
So is there anyway to put models in separate folders or better ways to manage models?
I'm not sure that this is a good strategy or not. But If I were in your situation I would try to solve it by following approach.
Let's consider we have two packages package a and package b.
package a
import ".../code/module2"
var StrA="Hi! I'm A and I'm calling B: "
func FuncA() string {
return "Inside A"
}
func AtoB() {
fmt.Println(StrA+b.FuncB())
}
package b
import ".../code/module1"
var StrB="Hi! I'm B and I'm calling A: "
func FuncB() string {
return "Inside B"
}
func BtoA() {
fmt.Println(StrB+a.FuncA())
}
You cannot use function AtoB() or BtoA() because it will make a loop. One possible way you can solve it by making sub-directory inside each module. Move those part of the code that makes loop. Like here AtoB() and BtoA().
Inside extraA.go:
package extended
import (
"fmt"
. ".../code/module1"
b ".../code/module2"
)
func AtoB() {
fmt.Println(StrA+b.FuncB())
}
I imported package a using . so that I can use a's object locally and imported package b to call FuncB(). I also move the BtoA() to another sub-directory inside module2.
Now I can use both function without making any loop.
package main
import (
extraA ".../code/module1/extended"
extraB ".../code/module2/extended"
)
func main() {
extraA.AtoB()
extraB.BtoA()
}
Output:
Hi! I'm A and I'm calling B: Inside B
Hi! I'm B and I'm calling A: Inside A

How to correctly import method from another package

I have the following simple project:
myapp/
|- mainlib/main.go
|- tables/sometable.go
In sometable.go I have:
package tables
import (
"fmt"
)
type TableName string
func (table TableName) GetDataFromDataSource() string {
return "getdatafromdatasource"
}
Those are methods, and now I want to use them in main.go:
package main
import t myapp/tables
type tableName t.TableName // and such "attempts"
I've tried:
t.GetDataFromDataSource()
t.tableName("string").GetDataFromDataSource()
tableName("string").GetDataFromDataSource()
and similar combinations and compiler says "undefined reference" still...
So, my question is: how to correctly use method from another package in such context? Of course my methods starts with captial letters and are exported. If I try to use simple function with same name (not method), then it works correctly...
This has nothing to do with packages, but with alias declaration vs type definition.
Let's take a simple example:
type A string
func (a A) Print() {
fmt.Println(a)
}
type B A
type C = A
func main() {
A("A").Print()
B("B").Print()
C("C").Print()
}
This fails to compile on line B("B").Print() with:
B("B").Print undefined (type B has no field or method Print)
The spec clearly spells out the difference in the type declarations section
The line type B A is a type definition:
A type definition creates a new, distinct type with the same
underlying type and operations as the given type, and binds an
identifier to it.
While the line type C = A is an alias declaration:
An alias declaration binds an identifier to the given type.
The former is a new type, so the receiver type A for method Print() will not match the type B.
The latter is just a name pointing to type A.
You'll want to change your code to the following, using type aliases:
import t myapp/tables
type tableName = t.TableName
tableName("string").GetDataFromDataSource()
And a few notes:
t.GetDataFromDataSource() can't work, it's a method and needs a receiver
t.tableName("string").GetDataFromDataSource() won't work, t.tableName is not a thing, or if it is, it's not exported
you can't talk about importing methods, only packages are imported. A method is either exported or not, but it's the package you import

Multiple sets of const names with scope in Go

I have a Go application that requires an unbounded number of sets of constants. The application also requires that I be able to map strings to (integer) consts, and vice versa at runtime. The names of the constants are guaranteed only to be valid identifiers, so it's a near certainty that there will be duplicate const names. In particular, each set of constants has an element called "Invalid". In C++11, I'd use enum classes to achieve scope. In Python, I'd probably use class variables. I'm struggling to find an idiomatic way to express this in Go. Options that I've looked at include:
Using a separate package for every set of consts. This has lots of disadvantages, because I'd rather the whole set be in the same package so that I can build support for these sets at the package level, and so that I can test the whole lot without overly complicating the test code to do multi-package testing at once.
first.go:
package first
type First int
const (
ConstOne First = iota
ConstTwo
Invalid = -1
)
func IntToCode(fi First)string { ... }
func CodeToInt(code string)First { ... }
second.go:
package second
type Second int
const (
ConstOne Second = iota
ConstTwo
Invalid = -1
)
func IntToCode(se Second)string { ... }
func CodeToInt(code string)Second { ... }
example.go:
import (
"first"
"second"
)
First fi = first.CodeToInt("ConstOne")
Second se = second.Invalid
Using the tried-and-true technique of a globally unique prefix for each const. Given, though, that the number of sets is really big, having to essentially invent and manage a bunch of namespaces using a coding convention is awkward at best. This option also forces me to modify the names of the consts (which is the whole point of using them).
first.go:
package mypackage
type First int
const (
FI_CONSTONE First = iota
FI_CONSTTWO
FI_INVALID = -1
)
func IntToCode(fi First)string { ... }
func CodeToInt(code string)First { ... }
second.go:
package mypackage
type Second int
const (
SE_CONSTONE Second = iota
SE_CONSTTWO
SE_INVALID = -1
)
func IntToCode(se Second)string { ... }
func CodeToInt(code string)Second { ... }
example.go:
package mypackage
import (
"first"
"second"
)
First fi = first.CodeToInt("ConstOne")
Second se = SE_INVALID
What's a better, more idiomatic solution? I'd love to be able to say things like:
First fi = First.Invalid
but I haven't been successful in coming up with an approach that allows this.
You could have separate packages for your separate code sets and a single package for defining the higher level functionality associated with codes and write tests for that higher level package.
I haven't compiled or tested any of this:
E.g. for a code set:
package product // or whatever namespace is associated with the codeset
type Const int
const (
ONE Const = iota
TWO
...
INVALID = -1
)
func (c Const) Code() string {
return intToCode(int(c)) // internal implementation
}
type Code string
const (
STR_ONE Code = "ONE"
...
)
func (c Code) Const() int {
return codeToInt(string(c)) // internal implementation
}
E.g. for the higher level functions package:
// codes.go
package codes
type Coder interface{
Code() string
}
type Conster interface{
Const() int
}
func DoSomething(c Coder) string {
return "The code is: " + c.Code()
}
// codes_product_test.go
package codes
import "product"
func TestProductCodes(t *testing.T) {
got := DoSomething(product.ONE) // you can pass a product.Const as a Coder
want := "The code is: ONE"
if got != want {
t.Error("got:", got, "want:", want)
}
}
Edit:
To retrieve the const for a particular code you could do something like
product.Code("STRCODE").Const()
Maybe it's better if Const() returns a Coder so that product.Code("ONE").Const() can be a product.Const. I think if you play around with it there are a few options and there will be a good one in there somewhere.

go how to check if a function exists

Is there any way to check if a func exists in Go?
In PHP I might do something like
if(function_exists('someFunction')) {
//...
}
but I have not been able to figure out how to do this in Go
Any help on this will be greatly received.
A little more context on what you're trying to do would help.
As you note in your own comment, if you try to call a function Go checks at compile-time if the function exists, most of the times.
One exception that comes to my mind is when you use interface{} and you want to check that a method exists before calling it. For this you can use type checks.
Example:
package main
import "fmt"
// a simple Greeter struct
// with a Hello() method defined
type Greeter struct {
Name string
}
func (m *Greeter) Hello() string {
return "hello " + m.Name
}
var x interface{}
func main() {
x = Greeter {Name:"Paolo"} // x is a interface{}
g,ok := x.(Greeter) // we have to check that x is a Greeter...
if ok {
fmt.Println(g.Hello()) // ...before being able to call Hello()
}
}
Another scenario I can think of is that you're creating your own tool for Go that requires parsing go files before compiling them. If so, Go provides help in the for of the parser package
There's no way to do that (and for good!). The reason is that Go is a compiled language and does not support loadable modules (yet, at least) so functions can't come and go at runtime, and hence whether or not a top-level function exists, you know by defintion: if a given source file imports a package containing the function of interest1, that function is visible in this source file. Or this function is declared in the same package this source file belongs to and hence it's also available. In all the other cases the function is not available. Note that a function might be compiled in the program but still not visible in a given source file while compiling, so the whole definition of visibility as you put it does not exist in Go.
On the other hand you might want some generality. Generality in Go is achieved via interfaces. You might define an interface and then require a type to implement it. Checking that a type implements an interface is done via a neat trick.
An update from 2021-12-29.
The support for loadable modules was added in Go 1.8 in the form of the plugin package and has since then matured to support most mainline platforms except Windows.
Still, this solution is not without problems—for instance, see #20481.
1Without renaming that module to nothing, but let's not touch this for now.
Provided your thing is an interface value, type assert, something like this:
if Aer, ok := thing.(interface{MethodA()}); ok {
Aer.MethodA()
}
If thing is a struct, assign it to an interface variable first,
because type assertions only work on interface values.
It wouldn't hurt to define a named interface instead of using the
nonce one, but for simple cases like this it's not worth it.
Recently I had a need for figuring out if a struct has a particular function or not.
Here is another way using reflection :
package main
import (
"fmt"
"reflect"
)
type FuncRegistry struct {}
func (fr FuncRegistry) Hi() {
fmt.Println("function Hi")
}
func (fr FuncRegistry) Hello() {
fmt.Println("function Hello")
}
func functionExists(obj interface{},funcName string) bool {
mthd := reflect.ValueOf(obj).MethodByName(funcName)
if mthd.IsValid() {
fmt.Printf("Function '%s' exists \n",funcName)
return true
}
fmt.Printf("Function '%s' does not exist\n",funcName)
return false
}
// Main function
func main() {
var fr FuncRegistry
functionExists(fr,"Hi")
functionExists(fr,"Hello")
functionExists(fr,"Fail")
}
This sounds a lot like a XY problem. Please tell what you are trying to do. As far as I know, this is something you can't really do the same way as in PHP.
However, you could create a map with function names as keys. Add the functions there manually or generate the contents by parsing the source files before the compilation or at run time. Parsing the source seems like a dirty hack though.

Resources