大家好,我是张锦涛。最近Rust社区/团队发生了一些变化,因此Rust再次进入了大多数人的视野。最近看到很多朋友说:Rust还值得学吗?社区不稳定?Rust和Go哪个更好?Rust还值得学习吗?如果有人问我这些问题,那么我的回答是:孩子只会做选择,我都要!当然,关于Rust和Go的问题并不新鲜,比如之前的一条推文:这篇文章,我将介绍如何用Go调用Rust。当然,在这篇文章中,我基本不会比较Go和Rust的功能,或者这种方法的性能。只是为了FunFFI和BindingFFI(ForeignFunctionInterface)被翻译为外部函数接口(为了简单起见,下文将使用FFI来指代)。最早的规范来自CommonLisp,写在wiki上,没去查。不过FFI这个概念/术语存在于我用过的大部分语言中,例如:Python、Ruby、Haskell、Go、Rust、LuaJIT等。FFI的作用简单来说就是让一种语言能够调用另一种语言,有时我们也用Binding来表示类似的能力。不同的语言会有不同的实现,比如Go中的cgo,Python中的ctypes,Haskell中的CAPI(之前就有ccall)等等,个人感觉在Haskell中使用FFI比其他语言更简单方便,但是这不是本文的重点,所以我不会展开。在这篇文章中,对于Go和Rust,他们的FFI需要和C语言对象进行通信,而这部分实际上是由操作系统根据API中的调用约定来完成的。我们开始谈正事吧。准备Rust示例程序Rust的安装和Cargo工具的基本使用,这里不再介绍。你可以去Rust的官网了解更多。要使用Cargo创建一个项目,我们首先准备一个目录来放置这个例子的代码。(我创建的目录叫做go-rust)然后使用Rust的Cargo工具创建一个名为rustdemo的项目,这里是因为我添加了--lib选项,使用它内置的库模板。?go-rustgit:(master)?mkdirlib&&cdlib?go-rustgit:(master)?cargonew--librustdemo创建库`rustdemo`包?go-rustgit:(master)?treerustdemorustdemo├──Cargo.toml└──src└──lib.rs1目录,2个文件PrepareRustcodeexterncratelibc;usestd::ffi::{CStr,CString};#[no_mangle]pubextern"C"fnrustdemo(name:*constlibc::c_char)->*constlibc::c_char{letcstr_name=unsafe{CStr::from_ptr(name)};让mutstr_name=cstr_name.to_str().unwrap().to_string();println!("Rust获取输入:\"{}\"",str_name);letr_string:&str="Rustsay:HelloGo";str_name.push_str(r_string);CString::new(str_name).unwrap().into_raw()}代码比较简单。Rust暴露的函数叫做rustdemo,它接收一个外部参数并打印出来。然后从Rust端设置另一个字符串。CString::new(str_name).unwrap().into_raw()转换为原始指针,供C语言稍后处理。要编译Rust代码,我们需要修改Cargo.toml文件以使其能够编译。请注意,我们在这里添加了crate-type=["cdylib"]和libc。[package]name="rustdemo"version="0.1.0"edition="2021"[lib]crate-type=["cdylib"][dependencies]libc="0.2"然后编译?rustdemogit:(master)?cargobuild--releaseCompilingrustdemov0.1.0(/home/tao/go/src/github.com/tao12345666333/go-rust/lib/rustdemo)在0.22秒内完成发布[优化]目标查看生成的文件,这是一个.so文件(这是因为我是linux环境,如果是其他系统环境就不一样了)?rustdemogit:(master)?lstarget/release/librustdemo.sotarget/release/librustdemo.所以准备Go代码,安装Go环境等就不赘述了,直接在我们的go-rust目录下继续操作即可。写入main.gopackagemain/*#cgoLDFLAGS:-L./lib-lrustdemo#include
