<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
近期 Rust 社群/團隊有些變動,所以再一次將 Rust 拉到大多數人眼前。
我最近看到很多小夥伴說的話:
這些問題如果有人來問我,那我的回答是:
小孩子才做選擇,我都要!
當然,關於 Rust 和 Go 的問題也不算新,比如之前的一條推文:
我在本篇中就來介紹下如何用 Go 呼叫 Rust。
當然,這篇中我基本上不會去比較 Go 和 Rust 的功能,或者這種方式的效能之類的,Just for Fun
FFI (Foreign Function Interface) 翻譯過來叫做外部函數介面(為了比較簡單,下文中都將使用 FFI 指代)。最早來自於 Common Lisp 的規範,這是在 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 的安裝和 Cargo 工具的基本使用,這裡就不介紹了。大家可以去 Rust 的官網進行了解。
我們先準備一個目錄用來放本次範例的程式碼。(我建立的目錄叫做 go-rust )
然後使用 Rust 的 Cargo 工具建立一個名叫 rustdemo 的專案,這裡由於我增加了 --lib 的選項,使用其內建的 library 模板。
➜ go-rust git:(master) ✗ mkdir lib && cd lib ➜ go-rust git:(master) ✗ cargo new --lib rustdemo Created library `rustdemo` package ➜ go-rust git:(master) ✗ tree rustdemo rustdemo ├── Cargo.toml └── src └── lib.rs 1 directory, 2 files
extern crate libc; use std::ffi::{CStr, CString}; #[no_mangle] pub extern "C" fn rustdemo(name: *const libc::c_char) -> *const libc::c_char { let cstr_name = unsafe { CStr::from_ptr(name) }; let mut str_name = cstr_name.to_str().unwrap().to_string(); println!("Rust get Input: "{}"", str_name); let r_string: &str = " Rust say: Hello Go "; str_name.push_str(r_string); CString::new(str_name).unwrap().into_raw() }
程式碼比較簡單,Rust 暴露出來的函數名叫做 rustdemo ,接收一個外部的引數,並將其列印出來。之後從 Rust 這邊再設定一個字串。
CString::new(str_name).unwrap().into_raw() 被轉換為原始指標,以便之後由 C 語言處理。
我們需要修改下 Cargo.toml 檔案以便進行編譯。注意,這裡我們增加了 crate-type = ["cdylib"] 和 libc 。
[package] name = "rustdemo" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] libc = "0.2"
然後進行編譯
➜ rustdemo git:(master) ✗ cargo build --release Compiling rustdemo v0.1.0 (/home/tao/go/src/github.com/tao12345666333/go-rust/lib/rustdemo) Finished release [optimized] target(s) in 0.22s
檢視生成的檔案,這是一個 .so 檔案(這是因為我在 Linux 環境下,你如果在其他系統環境下會不同)
➜ rustdemo git:(master) ✗ ls target/release/librustdemo.so target/release/librustdemo.so
Go 環境的安裝之類的這裡也不再贅述了,繼續在我們的 go-rust 目錄操作即可。
package main /* #cgo LDFLAGS: -L./lib -lrustdemo #include <stdlib.h> #include "./lib/rustdemo.h" */ import "C" import ( "fmt" "unsafe" ) func main() { s := "Go say: Hello Rust" input := C.CString(s) defer C.free(unsafe.Pointer(input)) o := C.rustdemo(input) output := C.GoString(o) fmt.Printf("%sn", output) }
在這裡我們使用了 cgo ,在 import "C" 之前的註釋內容是一種特殊的語法,這裡是正常的 C 程式碼,其中需要宣告使用到的標頭檔案之類的。
下面的程式碼很簡單,定義了一個字串,傳遞給 rustdemo 函數,然後列印 C 處理後的字串。
同時,為了能夠讓 Go 程式能正常呼叫 Rust 函數,這裡我們還需要宣告其標頭檔案,在 lib/rustdemo.h 中寫入如下內容:
char* rustdemo(char *name);
在 Go 編譯的時候,我們需要開啟 CGO (預設都是開啟的),同時需要連結到 Rust 構建出來的 rustdemo.so 檔案,所以我們將該檔案和它的標頭檔案放到 lib 目錄下。
➜ go-rust git:(master) ✗ cp lib/rustdemo/target/release/librustdemo.so lib
所以完整的目錄結構就是:
➜ go-rust git:(master) ✗ tree -L 2 . . ├── go.mod ├── lib │ ├── librustdemo.so │ ├── rustdemo │ └── rustdemo.h └── main.go 2 directories, 5 files
編譯:
➜ go-rust git:(master) ✗ go build -o go-rust -ldflags="-r ./lib" main.go ➜ go-rust git:(master) ✗ ./go-rust Rust get Input: "Go say: Hello Rust" Go say: Hello Rust Rust say: Hello Go
可以看到,第一行的輸出是由 Go 傳入了 Rust , 第二行中則是從 Rust 再傳回 Go 的了。符合我們的預期。
本篇介紹瞭如何使用 Go 與 Rust 進行結合,介紹了其前置關於 FFI 相關的知識,後續通過一個小的實踐演示了其完整過程。 感興趣的小夥伴可以自行實踐下,更多關於Go呼叫Rust外部函數介面前置的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45