Contents

Why Go vs Rust When You Can Have Go + Rust?

We often encounter the question of whether to use Go or Rust. After trying both Go and Rust for a while, I found that we can use cgo + Rust FFI. Since both have different advantages, we can just use both!

What is Rust FFI?

Rust FFI (Foreign Function Interface) is a tool that allows us to call functions and code in Rust from other languages such as C, C++, and Go smoothly and safely.

Let’s try it out

Create a Go Project

go-rust-ffi
├── lib                 <--- Rust lib
   └── rs-add
       ├── src
          └── lib.rs  <--- Rust lib src
       ├── build.rs    <--- Rust build script
       ├── Cargo.lock
       └── Cargo.toml
├── go.mod
├── LICENSE
├── main.go             <--- Go file
├── Makefile            <--- Make script
└── README.md

In lib, we can use cargo to create a Rust project for us.

cd lib
cargo new --lib rs-add

We’ll start with something simple like this in the src/lib.rs file:

#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
    a + b
}

Then we use cbindgen to generate a header file for us (or you can write it by hand).

cargo install cbindgen
cbindgen --lang c --output rs-add.h

Let’s build the Rust lib.

cargo build --release

We will get librs_add.so and librs_add.a. For now, let’s move them to ./lib to avoid confusion.

In main.go, we can call it via cgo like this:

package main

/*
#cgo LDFLAGS: -L./lib -l:librs_add.so
#include "./lib/rs-add.h"
*/
import "C"
import "fmt"

func main() {
    a := 10
    b := 20
    result := int(C.add(C.int(a), C.int(b)))
    fmt.Printf("Result: %d\n", result)
}

In the Go code, we use the import "C" statement to call the Rust function via FFI. This will use the header file to specify the add function and link the Rust lib to our Go code.

When building Go, we also need to include the lib.

CURRENT_DIR=$(pwd || echo ${PWD})
go build -ldflags="-r $(CURRENT_DIR)lib" -o dist/ ./...

Conclusion

Now that we know about Rust FFI and how we can use Rust in our Go code via FFI + cgo to make Go and Rust communicate, we don’t have to argue about whether to use Go or Rust anymore. We can take advantage of both, for example, using Go for the Router/Thread controller and Rust to help with hot functions. I have created an example that generates a QR code with Rust at go-rust-ffi. You can go and play with it.