与 Rust 互操作
本文展示如何结合 Kotlin/Native 和 Rust,发挥两种语言的优势。Rust 提供内存安全的高性能计算,Kotlin/Native 提供类型安全的上层接口。
项目背景
为什么结合 Rust
- Rust优势: 零成本抽象、内存安全、并发安全、极致性能
- Kotlin/Native优势: 多平台、简洁语法、协程、生态
kotlin
// Kotlin调用 - 简洁接口
fun processImage(data: ByteArray): ByteArray {
return rust_process_image(data)
}rust
// Rust实现 - 高性能逻辑
#[no_mangle]
pub extern "C" fn rust_process_image(
data: *const u8, len: usize
) -> *mut u8 {
// SIMD加速的图像处理
unsafe {
let input = std::slice::from_raw_parts(data, len);
process_with_simd(input)
}
}完整项目架构
项目结构
``
` KotlinRustDemo/ ├── rust/ │ ├── src/ │ │ ├── lib.rs # Rust库 │ │ ├── image.rs # 图像处理 │ │ └── crypto.rs # 加密算法 │ ├── Cargo.toml │ └── build.sh ├── kotlin/ │ ├── src/nativeMain/kotlin/ │ │ ├── RustBindings.kt # Kotlin->Rust绑定 │ │ └── Main.kt │ └── build.gradle.kts └── CMakeLists.txt
### Rust侧配置
```toml
# rust/Cargo.toml
[package]
name = "rust_lib"
version = "0.1.0"
edition = "2021"
[lib]
name = "rust_lib"
crate-type = ["cdylib", "staticlib"]
[dependencies]
rayon = "1.8" # 并行计算
image = "0.24" # 图像处理
aes-gcm = "0.10" # 加密
[profile.release]
opt-level = 3
lto = true
codegen-units = 1Kotlin侧配置
kotlin
// kotlin/build.gradle.kts
kotlin {
linuxX64 {
compilations.getByName("main") {
cinterops {
val rustLib by creating {
defFile(project.file("src/nativeInterop/cinterop/rustlib.def"))
packageName("rust")
// 链接Rust库
extraOpts("-libraryPath", "${projectDir}/../rust/target/release")
}
}
}
binaries {
executable {
linkerOpts("-L${projectDir}/../rust/target/release", "-lrust_lib")
}
}
}
}数据类型映射
基础类型
rust
// Rust侧
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {
a + b
}
#[no_mangle]
pub extern "C" fn mul_f64(a: f64, b: f64) -> f64 {
a * b
}kotlin
// Kotlin侧
@CName("add")
external fun rustAdd(a: Int, b: Int): Int
@CName("mul_f64")
external fun rustMulF64(a: Double, b: Double): Double字符串传递
rust
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[no_mangle]
pub extern "C" fn process_string(input: *const c_char) -> *mut c_char {
let c_str = unsafe { CStr::from_ptr(input) };
let rust_str = c_str.to_str().unwrap();
let result = rust_str.to_uppercase();
CString::new(result).unwrap().into_raw()
}
#[no_mangle]
pub extern "C" fn free_string(s: *mut c_char) {
unsafe {
if !s.is_null() {
drop(CString::from_raw(s));
}
}
}kotlin
@CName("process_string")
external fun rustProcessString(input: CPointer<ByteVar>): CPointer<ByteVar>?
@CName("free_string")
external fun rustFreeString(s: CPointer<ByteVar>?)
fun processString(input: String): String {
val result = rustProcessString(input.cstr.ptr)
return if (result != null) {
val str = result.toKString()
rustFreeString(result)
str
} else ""
}结构体传递
rust
#[repr(C)]
pub struct Point3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
#[no_mangle]
pub extern "C" fn distance(p1: Point3D, p2: Point3D) -> f64 {
let dx = p1.x - p2.x;
let dy = p1.y - p2.y;
let dz = p1.z - p2.z;
(dx*dx + dy*dy + dz*dz).sqrt()
}kotlin
data class Point3D(val x: Double, val y: Double, val z: Double)
@CName("distance")
external fun rustDistance(p1: CValue<CStructPoint3D>, p2: CValue<CStructPoint3D>): Double
fun calculateDistance(p1: Point3D, p2: Point3D): Double {
return cValue<CStructPoint3D> {
x = p1.x; y = p1.y; z = p1.z
}.let { cp1 ->
cValue<CStructPoint3D> {
x = p2.x; y = p2.y; z = p2.z
}.let { cp2 ->
rustDistance(cp1, cp2)
}
}
}数组处理
rust
#[no_mangle]
pub extern "C" fn sum_array(data: *const i32, len: usize) -> i64 {
unsafe {
let slice = std::slice::from_raw_parts(data, len);
slice.iter().map(|&x| x as i64).sum()
}
}
#[no_mangle]
pub extern "C" fn parallel_map(
data: *const f64,
len: usize,
output: *mut f64
) {
use rayon::prelude::*;
unsafe {
let input = std::slice::from_raw_parts(data, len);
let out = std::slice::from_raw_parts_mut(output, len);
input.par_iter()
.zip(out.par_iter_mut())
.for_each(|(&x, y)| {
*y = x.sin().powi(2) + x.cos().powi(2);
});
}
}kotlin
@CName("sum_array")
external fun rustSumArray(data: CPointer<IntVar>, len: ULong): Long
@CName("parallel_map")
external fun rustParallelMap(
data: CPointer<DoubleVar>,
len: ULong,
output: CPointer<DoubleVar>
)
fun sumArray(arr: IntArray): Long {
return arr.usePinned { pinned ->
rustSumArray(pinned.addressOf(0), arr.size.toULong())
}
}
fun parallelMap(arr: DoubleArray): DoubleArray {
val output = DoubleArray(arr.size)
arr.usePinned { inputPinned ->
output.usePinned { outputPinned ->
rustParallelMap(
inputPinned.addressOf(0),
arr.size.toULong(),
outputPinned.addressOf(0)
)
}
}
return output
}实战案例
案例一:图像处理
rust
// rust/src/image.rs
use image::{ImageBuffer, Rgb};
#[no_mangle]
pub extern "C" fn blur_image(
data: *const u8,
w: u32, h: u32,
output: *mut u8
) {
unsafe {
let input = std::slice::from_raw_parts(data, (w * h * 3) as usize);
let img = ImageBuffer::<Rgb<u8>, _>::from_raw(w, h, input.to_vec())
.unwrap();
let blurred = image::imageops::blur(&img, 5.0);
let out = std::slice::from_raw_parts_mut(output, (w * h * 3) as usize);
out.copy_from_slice(blurred.as_raw());
}
}kotlin
@CName("blur_image")
external fun rustBlurImage(
data: CPointer<ByteVar>,
width: UInt,
height: UInt,
output: CPointer<ByteVar>
)
fun blurImage(imageData: ByteArray, width: Int, height: Int): ByteArray {
val output = ByteArray(imageData.size)
imageData.usePinned { inputPinned ->
output.usePinned { outputPinned ->
rustBlurImage(
inputPinned.addressOf(0),
width.toUInt(),
height.toUInt(),
outputPinned.addressOf(0)
)
}
}
return output
}案例二:并行计算
rust
use rayon::prelude::*;
#[no_mangle]
pub extern "C" fn parallel_prime_count(n: u64) -> u64 {
(2..=n)
.into_par_iter()
.filter(|&num| is_prime(num))
.count() as u64
}
fn is_prime(n: u64) -> bool {
if n < 2 { return false; }
if n == 2 { return true; }
if n % 2 == 0 { return false; }
let limit = (n as f64).sqrt() as u64;
(3..=limit).step_by(2).all(|i| n % i != 0)
}kotlin
@CName("parallel_prime_count")
external fun rustParallelPrimeCount(n: ULong): ULong
fun countPrimes(n: Long): Long {
return rustParallelPrimeCount(n.toULong()).toLong()
}
// 性能对比
fun main() {
val n = 1_000_000L
val start1 = getTimeMillis()
val count1 = countPrimes(n) // Rust并行
val time1 = getTimeMillis() - start1
println("Rust: $count1 primes in ${time1}ms")
// 输出: Rust: 78498 primes in 125ms (8核CPU)
}性能对比
| 操作 | Kotlin/Native | Rust | Rust优势 |
|---|---|---|---|
| 图像模糊(1920x1080) | 850ms | 185ms | 4.6x |
| 并行质数计数(1M) | 520ms | 125ms | 4.2x |
| 字符串处理(100k) | 95ms | 42ms | 2.3x |
| 加密操作(AES-GCM,1MB) | 28ms | 12ms | 2.3x |
测试环境: Linux, Ryzen 7 5800X (8C/16T), 32GB RAM
最佳实践
内存管理
rust
// ✅ 正确:明确所有权
#[no_mangle]
pub extern "C" fn create_buffer(size: usize) -> *mut u8 {
let mut buf = vec![0u8; size];
let ptr = buf.as_mut_ptr();
std::mem::forget(buf); // 转移所有权
ptr
}
#[no_mangle]
pub extern "C" fn free_buffer(ptr: *mut u8, size: usize) {
unsafe {
drop(Vec::from_raw_parts(ptr, size, size));
}
}错误处理
rust
#[repr(C)]
pub struct RustResult {
pub success: bool,
pub value: i64,
pub error_code: i32,
}
#[no_mangle]
pub extern "C" fn safe_divide(a: i64, b: i64) -> RustResult {
if b == 0 {
RustResult {
success: false,
value: 0,
error_code: -1,
}
} else {
RustResult {
success: true,
value: a / b,
error_code: 0,
}
}
}Kotlin/Native 与 Rust 的组合提供了类型安全的接口和极致性能,适用于计算密集型应用、图像处理和高性能服务。