Why Go is Not an Island, but a Bridge
\n\nGo is a remarkable language. It's fast, compiled, with an excellent standard library. But let's be honest: in the real world, we rarely write everything from scratch in one language. You have an old, time-tested library in C that you'd hate to rewrite. Or a cool Python script for machine learning. Or you want to run Go logic directly in the browser.
\nAnd then the question arises: how to integrate Go with other languages? Don't worry, Go was specifically designed to be a good "neighbor". In this article on PythonLib, we'll break down three main ways to make your Go program friends with foreign code. You'll learn how cgo works, how to call Python functions via system calls, and even how to compile Go into WebAssembly.
Go Integration with C via cgo: The Classic Approach
\n\nThe most direct and powerful path is cgo. It's not a library, but a built-in Go mechanism that allows your code to directly call C functions. How does it work? You simply write the import "C" and before it — a comment with C code. The Go compiler will glue it all together.
Writing Your First Program with cgo
\n\nLet's write a simple example: call the standard printf from C. Create a file main.go:
package main\n\n/*\n#include <stdio.h>\n#include <stdlib.h>\n\nvoid hello_cgo(const char* name) {\n printf("Hello from C, %s!\\n", name);\n}\n*/\nimport "C"\nimport "unsafe"\n\nfunc main() {\n name := C.CString("Gopher")\n defer C.free(unsafe.Pointer(name))\n C.hello_cgo(name)\n}\n\n\nRun it: go run main.go. If you have GCC installed (or MinGW on Windows), everything will compile. You'll see "Hello from C, Gopher!". Magic!
Important: C.CString allocates memory in the C heap, so we must free it via C.free. Otherwise — a leak. Cgo requires discipline from you.
Passing Complex Types: Structures
\n\nOften you need to work not with strings, but with structures. Suppose we have a C library for working with matrices. We want to pass a Go structure into it. Let's do it:
\n\npackage main\n\n/*\ntypedef struct {\n int x;\n int y;\n int result;\n} Point;\n\nPoint add_points(Point a, Point b) {\n Point r;\n r.x = a.x + b.x;\n r.y = a.y + b.y;\n r.result = r.x + r.y;\n return r;\n}\n*/\nimport "C"\nimport "fmt"\n\ntype GoPoint struct {\n X, Y, Result int\n}\n\nfunc main() {\n a := C.Point{x: 10, y: 20}\n b := C.Point{x: 30, y: 40}\n r := C.add_points(a, b)\n\n goPoint := GoPoint{\n X: int(r.x),\n Y: int(r.y),\n Result: int(r.result),\n }\n fmt.Printf("Go received: Point{X:%d, Y:%d, Result:%d}\\n", goPoint.X, goPoint.Y, goPoint.Result)\n}\n\n\nNotice: we explicitly convert C types to Go types. Cgo cannot automatically map structures, so you are always responsible for the conversion. This is one of the main trade-offs of Go integration with the C language.
\n\nWhen cgo is Not Needed
\nDo not use cgo if:
\n- \n
- You just need to call a command in the terminal — use
os/exec. \n - You are writing cross-platform code — cgo complicates the build. \n
- Performance is not critical — cgo adds overhead for context switching. \n
Go Integration with Python: Scripting Smartly
\n\nPython and Go are an excellent pair. Go for speed and concurrency, Python for flexibility and ecosystem (NumPy, TensorFlow). How to make them friends? We have two approaches: "heavy" (via cgo and the Python C API) and "light" (via subprocesses).
\n\nMethod 1: Calling Python via os/exec (Simple and Reliable)
\n\nThe safest way for education is to run a Python script as a separate