You can keep the holy war about programming languages. Each of them combines the advantages and disadvantages. There is always an example when one language loses to another on a specific task. Some of them may well coexist side by side in one program. In this post I will tell you how to connect Go and Rust into one.
This post is the answer to
Why Go and Rust are not rivals and
Why Go and Rust are not rivals, but damn foes .
Rust and go have a lot of differences. A different approach to memory management, different ancestors, a different goal in the end. Their scope is intersected only partially. If rust cares more about safe memory management, then go tries to improve the readability of the code.
But there are languages and similarities. Both languages are compiled. Both are trying to incorporate the best of the already proven practices. And most importantly, go and rust have a mutual friend. One of the oldest languages. Perhaps the most common and cross-platform. The C language. Both of them have tools for calling a shared code. So no one bothers to bind them together at the linking stage and make them pull each other’s functions.
')
Let's start with rust
The first thing to do before building the code for rust is to describe the cargo package. Since go can only create executable files, the rust code will have to be a static library. To do this, create a file Cargo.toml:
[package] name = "hello" version = "0.1.0" autors = ["Lain-dono <lain.dono@gmail.com>"] [lib] name = "hello" path = "lib.rs" crate-type = ["staticlib"] [dependencies] libc = "0.1.8"
The
package
section describes the
package
meta-information, the
lib
section describes what to build and how, and the
dependencies
section manages dependencies. Dependence only on the standard C library. The result is stored in the folder
/target/debug
or
/target/release
, depending on the transferred cargo keys.
Now turn the code. To start importing the necessary.
extern crate libc; use std::ffi::{CStr, CString};
Now we need to decide what exactly we will call from the code on go. Let it be a function with one string parameter:
extern { fn HelloFromGo(name: *const libc::c_char); }
In turn, we need to declare a function that can be connected and called go. Note the
#[no_mangle]
and
extern "C"
. The first one says to rust-y, that you should not alter the name of the function in the compilation process in any way, and the second, that you should export the function as a sishna.
#[no_mangle] pub extern "C" fn hello_from_rust(name: *const libc::c_char) { let buf_name = unsafe { CStr::from_ptr(name).to_bytes() }; let str_name = String::from_utf8(buf_name.to_vec()).unwrap(); println!("go\t: {}", str_name);
A little further call the go-function.
let hello = CString::new(" :3 , Nim ?").unwrap(); unsafe { HelloFromGo(hello.as_ptr()); } }
Turn go
Now we need to write code calling
hello_from_rust
and containing the main function.
Declare a package called main and import the output library:
package main import "fmt"
Now we should import everything we wrote on rust. When invoking the build utility, go also calls the linker. Let's agree that we have a release version of the library written on rust. And since we have a static library, we should also import
m
and
dl
.
import "C"
Next you need to write a function that will be called from rust. The comment before the f is telling the compiler to go import it.
It remains only to write the entry point to the application. Here, the
hello_from_rust
function external to go is
hello_from_rust
func main() { C.hello_from_rust(C.CString(" Rust!")) }
Conclusion
That's all. It now remains to secure the friendly union with the Makefile:
build: cargo build --release go build main.go clean: cargo clean rm -f "./main"
You can safely compile and run. The code can be taken
here .
: wq