access main struct from packages - go

Please consider this sample go code, also here: https://play.golang.org/p/ZcNy_crAg51
package main
import (
"fmt"
"play.ground/foo"
)
type SampleStruct struct {
token int
}
var (
MainSampleVar = SampleStruct{token: 333}
)
func main() {
fmt.Println("Hello!")
b := foo.Auxstruct{AuxToken: 4333}
fmt.Printf("b: %#v\n", b)
foo.AuxHello()
}
-- go.mod --
module play.ground
-- foo/foo.go --
package foo
import "fmt"
type Auxstruct struct {
AuxToken int
}
func AuxHello() {
fmt.Println("Aux says hello!")
}
I am able to access foo.Auxstruct in main.go.
Is it possible to go the other direction and access main.SampleStruct in package foo?
Please show how / explain.

This is not possible in Go because it would result in a circular dependency: play.ground imports play.ground/foo and play.ground/foo imports play.ground. Go doesn't allow such circular dependencies because they have many disadvantages.
There are several possible solutions:
You could move SampleStruct into the play.ground/foo package. This way you can use SampleStruct in play.ground/foo and import it into play.ground.
Alternatively, move SampleStruct into its own package, for example play.ground/bar. This way you can import play.ground/bar into both play.ground/foo and play.ground.

Related

modifying imported functions in go

I could override the builtin print() function's behavior by defining another print() in scope, as in https://play.golang.org/p/Y2ly31oXU67
Is it possible in go to alter the behavior on-the-fly of an imported function, say fmt.Println()?
If you want to 'alter' a builtin function, look at the very fine monkey patch utility https://github.com/bouk/monkey (And pay attention to the warnings, it's only really useful in test functions, and I for one reject any prod code that imports that package)
Import a different package with name "fmt" and implement whatever functions you need in that package. Here's an example:
File go.mod:
module test
File main.go
package main
import (
"test/fmt"
)
func main() {
fmt.Println("Hello, playground")
}
File fmt/fmt.go:
package fmt
import (
"fmt"
"log"
)
func Println(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
log.Printf(msg)
}
Run it on the playground.
The code in this answer does not modify the imported function as asked in the question.

I can't import "cloud.google.com/go/datastore"

I can't understand why this :/
I tried go get -u ** with every url that I found.
Thanks
Golang:
$ go version
go version go1.13.3 windows/amd64
Source test:
package main
import (
"fmt"
"cloud.google.com/go/datastore"
)
var client *datastore.Client
func main() {
fmt.Println("Work")
}
Error:
$ go run main.go
# google.golang.org/grpc/internal/transport
..\..\..\..\google.golang.org\grpc\internal\transport\http_util.go:270:23: cannot use hf (type "vendor/golang.org/x/net/http2/hpack".HeaderField) as type
"golang.org/x/net/http2/hpack".HeaderField in argument to d.processHeaderField
..\..\..\..\google.golang.org\grpc\internal\transport\http_util.go:675:23: cannot use "golang.org/x/net/http2/hpack".NewDecoder(http2InitHeaderTableSize,
nil) (type *"golang.org/x/net/http2/hpack".Decoder) as type *"vendor/golang.org/x/net/http2/hpack".Decoder in assignment
Go requires you make use of any package that you import. In this case you are importing "cloud.google.com/go/datastore" but not doing anything with it. The global variable that you declared is also not being used. Since it seems you are just trying to test, so I would recommend you do something with it (atleast print it). Like-
package main
import (
"fmt"
"cloud.google.com/go/datastore"
)
var client *datastore.Client
func main() {
fmt.Println(client)
}

cgo doesn't export functions in imported packages

I'm trying to build existed Go package into C shared library and header using CGO.
I built the package with -buildmode c-shared as documented.
-buildmode=c-shared
Build the listed main package, plus all packages it imports,
into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment.
Requires exactly one main package to be listed
And used //export Func to expose functions as C symbols.
All //export functions in main package are exported properly. However when I moved those functions to sub-package (with //export), those functions are not exported. I imported the sub-package in main package, too.
Here's my code.
main.go
package main
import "C"
import (
"fmt"
_ "github.com/onosolutions/archanan-cgo/c"
"math/rand"
)
// FuncInMain generates a random integer.
//export FuncInMain
func FuncInMain(max C.int) C.int {
return C.int(rand.Intn(int(max)))
}
func main() {
fmt.Printf("Hello World %d!\n", int(FuncInMain(256)))
}
c/c.go
package c
import "C"
import (
"math/rand"
)
// FuncInSubPackage generates a random integer.
//export FuncInSubPackage
func FuncInSubPackage(max C.int) C.int {
return C.int(rand.Intn(int(max)))
}
Then only FuncInMain is exported.
I read through CGO documentation, but there's nothing saying about exporting in sub-packages. The only clue I got is through go help buildmode, but it said that all imported sub-packages will be compiled. I'm not sure whether it isn't supported or I missed some configurations.
I'd love to achieve that to be able to modularize //export functions.
Both of them have own C.type, so as far as I know, there's no way to import function with C.type but using linking.
I didn't tried, but give it a chance:
import _ "unsafe"
//go:linkname FuncInSubPackage c.FuncInSubPackage
//export FuncInSubPackage
func FuncInSubPackage(max C.int) C.int

Why are Go C types different when they come from different modules?

In Go, I have a compile error due to incompatible types which I cannot explain. I'm using the "C" module. A minimum example consists of the following 2 files:
package module
import "C"
type T struct {
X C.int
}
and a main program
package main
import (
"fmt"
"sandbox/module"
)
import "C"
func f() *module.T {
var x C.int = 42
return &module.T{X: x}
}
func main() {
fmt.Printf("value: %d", f().X)
}
This fails to compile with the message
./main.go:12: cannot use x (type C.int) as type module.C.int in field value.
For some reason the compiler thinks that C.int is not equal to module.C.int.
It must have something to do with the C module and the fact that the code is spread across 2 modules because it suddenly works if I switch from C.int to plain int.
Why does this piece of code not compile? What would be the proper solution to make it compile without squashing all code together in one module?
I'm using the latest Go compiler 1.9.2 on Ubuntu 16.04.
Command cgo
Go references to C
Cgo translates C types into equivalent unexported Go types. Because
the translations are unexported, a Go package should not expose C
types in its exported API: a C type used in one Go package is
different from the same C type used in another.
You say, "For some reason the compiler thinks that C.int is not equal to module.C.int." As the cgo command documentation explains, unexported Go types in different packages are not equal.
Don't expose C types in an exported API. For example,
module.go:
package module
type T struct {
X int
}
main.go:
package main
import (
"fmt"
"sandbox/module"
)
import "C"
func f() *module.T {
var x C.int = 42
return &module.T{X: int(x)}
}
func main() {
fmt.Printf("value: %d\n", f().X)
}
Output:
value: 42

Import vars/consts from main in subpackage

I have a Go project at $GOPATH/dalu/myproject with the following files :
main.go:
package main
import "dalu/myproject/subpackage"
var GV string = "World"
func main() {
subpackage.Hello()
}
subpackage/subpackage.go:
package subpackage
import (
"fmt"
"dalu/myproject"
)
func Hello() {
//? fmt.Println("Hello"+GV)
}
Bonus (if I could):
I tried something similar with more subpackages and when trying to import a subpackage in main that imports another subpackage which imports the first mentioned subpackage I get "import cycle not allowed"
As the compiler so nicely said, Go doesn't allow cyclic dependencies, and unlike C++ there are no forward declarations tricks to be done here.
if you have a state where:
A imports B AND B imports A
it measns you need to move whatever they share between them to package C, and do:
A imports B, C AND B imports C
and everyone's happy!
or in your example, add a file called dalu/myproject/gv/gv.go and in it define this GV. Then import it in both main and subpackage

Resources