rust字符串数据类型String、str、CString和CStr

在 Rust 中,处理字符串时有四种主要的类型:StringstrCString 和 CStr。理解它们之间的区别至关重要,特别是当需要与 C 语言代码进行交互时。

1. 核心区别概览 

类型是否拥有所有权是否可变用途适用场景
String Rust 原生,堆分配,动态大小 Rust 内部使用,可增长的字符串
str Rust 原生,不可变,编译时已知大小 字符串字面量、切片引用
CString C 兼容,堆分配,以 \0 结尾 需要传递拥有所有权的字符串给 C 函数时
CStr C 兼容,不可变,引用,以 \0 结尾 需要从 C 函数接收字符串引用或处理 C 风格字符串常量时

2. String 和 str (Rust 原生字符串)

这两个是用于日常 Rust 编程的标准字符串类型。
String
  • 特点: 拥有所有权,存储在堆上,可增长,UTF-8 编码。
  • 使用场景:
    • 构建在运行时需要修改或增长的字符串(例如用户输入、文件读取)。
    • 需要在函数间传递所有权时。
str (字符串切片,通常写作 &str)
  • 特点: 不拥有所有权,是对 String 或静态存储区的不可变引用,UTF-8 编码。
  • 使用场景:
    • 函数参数:高效地传递字符串数据而不转移所有权或复制数据。
    • 字符串字面量:let s = "hello"; 中 "hello" 的类型就是 &'static str
    • 从 String 中获取子串。

3. CString 和 CStr (C 语言兼容字符串)

这两个类型专门用于 Rust 和 C 语言代码(Foreign Function Interface, FFI)之间的互操作。C 语言要求字符串必须以空字符(null terminator, \0)结尾。
CString
  • 特点: 拥有所有权,存储在堆上,以 \0 结尾,内部不能包含 \0
  • 使用场景:
    • 最重要场景: 将一个 Rust 字符串传递给一个期望拥有所有权的 C 函数(例如调用 C 库的 API)。
    • 它提供安全保障,确保字符串符合 C 语言的要求,并且不包含意外的空字符。
use std::ffi::CString;

let c_string = CString::new("Hello C!").expect("CString::new failed");
// 现在可以将 c_string 传递给外部的 C 函数
unsafe {
    // some_c_function(c_string.as_ptr());
}
// 当 c_string 离开作用域时,内存安全释放
CStr
  • 特点: 不拥有所有权,是对内存中以 \0 结尾的 C 风格字符串的不可变引用,内部不能包含 \0
  • 使用场景
    • 最重要场景: 从 C 函数接收一个字符串指针(例如从 C 库读取配置字符串)。
    • 表示一个静态的 C 语言字符串常量。
use std::ffi::CStr;
use std::os::raw::c_char;

// 假设我们从 C 代码中获得一个指针
let c_ptr: *const c_char = /* get from C */;

// 使用 unsafe 块将其转换为安全的 CStr 引用
let c_str_ref = unsafe { CStr::from_ptr(c_ptr) };

// 可以将其转换为 Rust 原生的 &str 使用
let rust_str: &str = c_str_ref.to_str().expect("Contains invalid UTF-8");
println!("来自 C 的字符串:{}", rust_str);
总结要点
  1. 日常 Rust 编程: 只用 String 和 &str
  2. 与 C 语言 FFI 交互: 必须使用 CString(传递所有权到 C)和 CStr(从 C 获取引用)。
  3. 安全性: CString 和 CStr 保证了 C 语言要求的空字符结尾格式,并且它们的方法通常在 unsafe 块内使用,需要开发者确保指针的有效性。

 

posted @ 2025-11-28 10:22  PKICA  阅读(35)  评论(0)    收藏  举报