[心得] 用 Rust 撰写 Ruby gem (3)

楼主: Neisseria (Neisseria)   2016-12-01 16:57:48
在最后一篇中,我们写一个 matrix 的例子
我们仍然会使用 struct,但在 struct 中会再包 2D vector
[Update]
加入释放内存相关程式码,冏rz
想看程式码的板友,可到以下 repo
https://github.com/cwchentw/libmatrix-rust-demo
首先,用 Rust 撰写 library 部分程式码
#[repr(C)]
pub struct Matrix {
m: Vec<Vec<f64>>,
}
#[no_mangle]
pub extern "C" fn matrix_new(nrow: usize, ncol: usize) -> *mut Matrix {
let mut m = Vec::new();
for j in 0..(nrow) {
let mut n = Vec::new();
for i in 0..(ncol) {
n.push(0.0);
}
m.push(n);
}
Box::into_raw(Box::new(Matrix { m: m }))
}
#[no_mangle]
pub extern "C" fn matrix_get_at(matrix: *const Matrix, row: usize, col: usize)
-> f64 {
unsafe { (*matrix).m[row][col] }
}
#[no_mangle]
pub extern "C" fn matrix_set_at(matrix: *mut Matrix, value: f64,
row: usize, col: usize) {
unsafe { (*matrix).m[row][col] = value; }
}
#[no_mangle]
pub extern "C" fn matrix_free(matrix: *mut Matrix) {
if matrix.is_null() {
return
}
unsafe { Box::from_raw(matrix); }
}
虽然,我们没有真正实作 matrix 的处理,只写了 getter/setter。
但是,这只是展示使用 2D vector 的程式,就请各位板友包涵
同样地,加入释放内存相关的程式码
接着,撰写相关的 C 程式码
#include <stdio.h>
void* matrix_new(size_t, size_t);
double matrix_get_at(void*, size_t, size_t);
void matrix_set_at(void*, double, size_t, size_t);
void matrix_free(void*);
int main() {
void* m = matrix_new(3, 3);
printf("(1, 1) = %lf\n", matrix_get_at(m, 1, 1));
matrix_set_at(m, 99, 1, 1);
printf("(1, 1) = %lf\n", matrix_get_at(m, 1, 1));
matrix_free(m);
return 0;
}
同样地,用 void* 接 Rust 的 struct
接着,撰写相关的 Ruby 程式码
require 'ffi'
require 'objspace'
module MyLib
extend FFI::Library
ffi_lib 'c'
ffi_lib 'target/release/libmatrix.so'
attach_function :matrix_new, [:int, :int], :pointer
attach_function :matrix_get_at, [:pointer, :int, :int], :double
attach_function :matrix_set_at, [:pointer, :double, :int, :int], :void
attach_function :matrix_free, [:pointer], :void
class Matrix
def initialize(row, col)
@m = MyLib::matrix_new(row, col)
ObjectSpace.define_finalizer(self, self.class.finalize)
end
def self.finalize
proc { MyLib::matrix_free @m }
end
def get_at(row, col)
MyLib::matrix_get_at(@m, row, col)
end
def set_at(value, row, col)
MyLib::matrix_set_at(@m, value, row, col)
end
end
end
m = MyLib::Matrix.new(3, 3)
puts "(1, 1) = #{m.get_at(1, 1)}"
m.set_at(99, 1, 1)
puts "(1, 1) = #{m.get_at(1, 1)}"
同样地,稍微包装函式库,让语法更接近 Ruby 的语法
透过以上数个范例,可知 Rust 的确有潜力用在 Rugy gem 的撰写
不过 Rust 上手难度偏高,板工目前也还在跟 Rust 的编译器奋战中 Orz
而且,Rust 的能见度和相关资源仍然较少,也是需要考虑的点
是否要将 Rust 引入自己下一个专案中,就请各位板友自行判断
作者: mars90226 (火星人)   2016-12-01 20:36:00
推!Rust真的很难啊
作者: lc85301 (pomelocandy)   2016-12-01 22:35:00
猛!
作者: danny8376 (钓到一只猴子@_@)   2015-01-18 09:49:00
我是不是该来补一篇 用Crystal写Ruby gem 啦XDDD毕竟crystal比rust年轻啊w

Links booklink

Contact Us: admin [ a t ] ucptt.com