一文解决Rust字符串:String,str,String,str,CString,CStr

news2024/12/24 10:19:49

一、str和&str和String的区别

1.存放位置,可变不可变:

str来源于Rust本身的数据类型,而String类型来自于标准库。首先看一下str 和 String之间的区别:String是一个可变的、堆上分配的UTF-8的字节缓冲区。而str是一个不可变的固定长度的字符串,如果是从String解引用而来的,则指向堆上,如果是字面值,则指向静态内存。

2.来看一个比较奇怪的例子
let s:&str="abcd";
char *s="abcd";

在C语言中,s是一个指针类型,指向一个字符串,但是它不知道长度,操作不安全。
在Rust中,s的类型是&str,而“abcd”是str类型,这里的“abcd”就是字符串字面值,存放在Stack上的。s 是切片,切片是一个结构体,包含两个字段,一个是指向数据的指针,另一个是数据的长度。因此,我们有可能采用必要的措施,安全的使用变量 s,这就是比C语言更安全的地方。

3.String
#[derive(PartialOrd, Eq, Ord)]
pub struct String {
    vec: Vec<u8>,
}

切片 &str 虽然可以安全使用,但是,我们很难动态修改其内容 —— 其地址、长度都是固定的。于是 Rust 提供了数据类型 String。String 包含了数据指针、数组容量、数据长度等三个字段。如果新修改的数据长度在其容量范围内,数据可以原地修改。如果新修改的数据长度超出了容量范围,它可以重新申请更大的内存。于是我们看到,String 和 &str 是两个完全不一样的结构体。为什么字符串要保留这两种形式?原因就是效率。Rust 希望在数组容量不会变化的时候,用 &str。在数组长度可能发生变化的情况下,使用 String。
补充几点关于String的:String 总是 “有效的” UTF-8,Rust字符串只能是UTF-8的类型。另外,不能用索引访问 String,因为有些字符的编码可能是多个字节,取到中间就是没有意义的。

4.&str或str转String
let s: String = "hello".to_string();
let t: String = String::from("hello");
5.String转&str或str

在 Rust 中,凡是需要用 &str 的地方,都可以直接用 &String 类型的数据。&String和&str其实也是差不多的。

fn greet(s: &str) {
    ...
}
fn main() {
    let s: String = String::from("hello");
    greet(&s);
}

那么如何选择使用&str还是String呢?
规则很简单,一般情况下,&str 用于只读数据,String 用于可修改的数据。

二、CString和CStr或&CStr

1.CString和CStr

对于C语言来说,字符串有两种,一种是共享的只读字符串 char * ,不能修改。另一种是动态分配的可变字符串 char [],可以修改。
而在Rust里面,字符串是由字符的 UTF-8 编码组成的字节序列。表示的类型有很多种。
字符串则比较复杂,Rust 中的字符串,是一组u8组成的 UTF-8 编码的字节序列,字符串内部允许NULL字节;但在 C 中,字符串只是指向一个char的指针,用一个NULL字节作为终止。
我们需要做一些特殊的转换,在 Rust FFI 中使用std::ffi::CStr,它表示一个NULL字节作为终止的字节数组,可以通过 UTF-8 验证转换成 Rust 中的&str。
CStr:表示以空字符终止的 C 字符串或字节数组的借用,属于引用类型。一般用于和 C 语言交互,由 C 分配并被 Rust 借用的字符串。
CString:表示拥有所有权的,中间没有空字节,以空字符终止的字符串类型。一般用于和 C 语言交互时,由 Rust 分配并传递给 C 的字符串。
下面这段代码,在这里get_string使用CStr::from_ptr从C的char*获取一个字符串,并且转化成了一个String。

fn get_string() -> String {
unsafe {
let raw_string: *mut c_char = char_func();
let cstr = CStr::from_ptr(raw_string);
cstr.to_string_lossy().into_owned()
}
}

和CStr表示从C中来,rust不拥有归属权的字符串相反,CString表示由rust分配,Rust拥有所有权,可以进行修改,用以传给C程序的字符串。

use std::ffi::CString;
use std::os::raw::c_char;
extern {
fn my_printer(s: *const c_char);
}

let c_to_print = CString::new("Hello, world!").unwrap();
unsafe {
my_printer(c_to_print.as_ptr()); // 使用 as_ptr 将CString转化成char指针传给c函数
}
2.CString 是一种类型,表示一个拥有的、C兼容的、以null结尾的字符串,中间没有null字节。

这种数据类型的目的是基于 Rust 的字节切片或 vector 数组生成 C 语言兼容的字符串。这种类型的实例需要确保字节数据中间不包含内部 0 字节(“null字符”),最后一个字节为0(“null终止符”)。
CString 与 &CStr 的关系就像 String 和 &str 的关系一样:CString、String 自身拥有字符串数据,而 &CStr、&str 只是借用数据而已。

3.输出指向 C 字符串的裸指针

CString 基于 Deref trait 实现了as_ptr方法。该方法给出一个 *const c_char 类型的指针,可以把这个指针传递给外部能够处理 null结尾的字符串的函数,例如 C 语言的 strdup() 函数。如果 C 语言代码往该指针所知的内存写入数据,将导致无法预测的结果。因为 C 语言所接受的这样的裸指针不包含字符串长度信息。

4.输出 C 字符串的切片

也可以使用 CString::as_bytes 方法从 CString 获取 &[u8] 切片。以这种方式生成的切片不包含尾部 null 终止符。这在调用一个外部函数时非常有用,该函数接受一个不一定以 null结尾的 *const u8参数,再加上另一个字符串长度的参数,比如 C 的 strndup()。当然,您可以使用 len 方法获得切片的长度。
如果想得到一个以 null 结尾的 &[u8] 切片,可以使用 CString::as_bytes_with_nul 方法。
无论获得 null 结尾的,还是没有 null 结尾的切片,都可以调用切片的 as_ptr 方法获得只读的裸指针,以便传递给外部函数使用。

三、综合比较

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端零基础入门-002-集成开发环境

本篇目标 了解市面上常用的前端集成开发环境&#xff08;ide&#xff09;掌握 HBuiberX 的使用&#xff1a;下载安装&#xff0c;新建项目、网页、运行网页。 内容摘要 本篇介绍了市面上流行的几款前端集成开发环境&#xff08;ide&#xff09;&#xff0c;并介绍了 Hbuilde…

华为OD机试 - 按索引范围翻转文章片段(Java) | 机试题算法思路 【2023】

使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12201821.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 按索引范围翻转文章…

【黄啊码】什么是ElasticSearch?它会替代MySQL成为主流吗?如何优化?TP5如何接入ElasticSearch?

什么是ElasticSearch&#xff1f; Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析 引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性&#xff0c;能使数据在生产环境变得更有价值。 Elasticsearch 的实现原理主要分…

「TCG 规范解读」第8章 TPM工作组 TPM 1.2中 SHA1的使用

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Alli…

Windows Server 2008 R2安装onlyoffice【docker】

目录 前言 准备工作 安装docker 安装onlyoffice 常见问题 前言 目前docker for windows只能在windows10/11上安装&#xff0c;其他的windows版本只能使用Docker Toolbox来安装&#xff0c;使用该工具安装的docker其实是借助了Oracle VM VirtualBox虚拟机来运行的&a…

简历的专业技能怎么写?排版需要注意的事项

一、简历的专业技能怎么写? 首先,先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几 天时间学习一下,然后在简历上可以写上自己了解这个技…

使用sshdo限制incoming ssh只能执行指定命令

前言系统管理员经常面临一个问题&#xff0c;如何将用户的incoming ssh限制在一个命令白名单里&#xff0c;达到安全的目的。本文介绍sshdo工具&#xff0c;来实现该功能。仓库地址https://github.com/wanlinwang/sshdo安装tar xzf sshdo-1.1.tar.gz #如果是直接clone仓库则无需…

JVM学习笔记六:运行时数据区之堆

目录 概述 堆空间内部结构 JDK7版本 JDK8版本 堆空间的内存划分 堆空间大小设置参数 概述 Java堆是虚拟机所管理的内存中最大的一块&#xff0c;其在JVM启动时即被创建&#xff0c;并且空间大小也被确定&#xff08;这里是不考虑Java8之后以本地内存来实现的元空间&…

连续时间信号与离散时间信号

前言 《信号与系统》是一门很难的课&#xff0c;也是许多学校考研要考的专业课&#xff0c;由于每周只有两节课&#xff0c;所以每次上完都要及时的去复习&#xff0c;这里参考的教材是奥本海姆著作&#xff0c;刘海棠译&#xff0c;北京&#xff1a;电子工业出版社&#xff0…

实践数据湖iceberg 第四十课 iceberg的sql运维方式(合并文件、合并元数据、清理历史快照)

系列文章目录 实践数据湖iceberg 第一课 入门 实践数据湖iceberg 第二课 iceberg基于hadoop的底层数据格式 实践数据湖iceberg 第三课 在sqlclient中&#xff0c;以sql方式从kafka读数据到iceberg 实践数据湖iceberg 第四课 在sqlclient中&#xff0c;以sql方式从kafka读数据到…

只因小黑子:SVG

小黑子的SVG复习SFV画布1. 初始SVG2. SVG绘制矩形、圆形和椭圆形2.1 rect 矩形2.2 circle 圆形2.3 ellipse 椭圆4. SVG绘制线条、多边形和多线条4.1 line 线条4.2 polygon 多边形4.3 polyline 多线条5. SVG绘制文本 text6. SVG绘制路径 path7. SVG描边属性8. SVG 模糊和阴影效果…

MySQL安装配置教程(超级详细、保姆级)

一、 下载MySQL Mysql官网下载地址&#xff1a;https://downloads.mysql.com/archives/installer/ 选择想要安装的版本&#xff0c;点击Download下载 本篇文章选择的是5.7.31版本 二、 安装MySQL 选择设置类型 双击运行mysql-installer-community-5.7.31.0.msi&#xff0c;…

车载以太网 - 测试用例设计 - 时间参数 - 11

前面已经介绍过DoIP相关的时间参数信息,然而对于时间参数信息相关的测试用例该如何设计呢?个人认为这是用例中最好设计的一类,这类的用例只需要按照定义去设计写测试用例即可,难的是自动化脚本开发和手动测试执行。毕竟时间参数一般都是毫秒级的验证,就算是秒级的我们也很…

【项目管理】对管理的认识与思考

在进入职场一段时间后&#xff0c;我们不免会对管理有一些接触&#xff0c;可能会自己带团队、可能会到管理岗位等等&#xff1b;做管理重要的就是对于不同层级的管理。 管理是一门艺术&#xff0c;在谈到管理时&#xff0c;我们首先想到的应该是管人、带团队或者是一个部门或公…

matplotlib学习笔记(持续更新中…)

目录 1. 安装&#xff0c;导入 2. figure&#xff0c;axes&#xff08;图形&#xff0c;坐标图形&#xff09; 2.1 figure对象 2.2 axes对象 2.3 代码演示 2.3 subplot() 方法 3. 图表的导出 3.1 savefig() 方法 3.2 代码演示 1. 安装&#xff0c;导入 pip install m…

Python —— Windows10下配置Pytorch环境(完整流程)

最终效果 配置流程 一、下载安装显卡驱动 1、查看设备管理器显卡是否为NVIDIA&#xff0c;并确定显卡型号 2、根据显卡型号然后NVIDIA官网下载安装显卡驱动 下载完成后&#xff0c;双击一步一步执行即可。 3、安装完成驱动后&#xff0c;打开cmd终端输入"nvidia-smi"…

JVM学习笔记五:运行时数据区之本地方法栈

目录 概述 本地方法&#xff08;Native Method&#xff09; 使用本地方法的原因 本地方法栈 执行流程 概述 如果要了解本地方法栈的作用&#xff0c;首先需要了解本地方法库和本地方法接口。 本地方法接口是Java代码调用其他非Java代码的接口&#xff0c;本地方法库是其他…

观看课程领奖品!Imagination中国区技术总监全面解读 IMG DXT GPU

此前&#xff0c;我们发布了一系列关于 IMG DXT GPU 的介绍&#xff0c;为了让更多读者了解其背后的技术及应用方向&#xff0c;我们特别邀请 Imagination 中国区技术总监艾克录制全新在线课程&#xff0c;为大家全面解读IMG DXT GPU。 点击这里&#xff0c;马上注册观看&…

函数的栈帧的创建和销毁

文章目录本章主题&#xff1a;一.什么是函数栈帧1.什么是栈2.什么是函数栈帧二.理解函数栈帧能解决什么问题呢&#xff1f;三.函数栈帧的创建和销毁解析1.预备知识&#xff08;1&#xff09; 认识相关寄存器和汇编指令&#xff08;2&#xff09;栈帧空间的维护2.解析函数栈帧的…

uniapp 引入彩色symbol和 指令权限

uniapp 引入iconfont图标库彩色symbol 1&#xff0c;先去阿里巴巴矢量图标库登录 然后点击下载至本地 2.下载本地&#xff0c;然后解压文件夹 3.打开终端cmd命令窗口 npm安装全局包npm i -g iconfont-tools 4.终端切换到上面解压的文件夹里面&#xff0c;运行iconfont-too…