当前位置: 首页 > news >正文

Rust~String、str、str、String、Box<str> 或 Box<str>

Rust语言圣经中定义

str

Rust 语言类型大致分为两种:基本类型和标准库类型,前者由语言特性直接提供,后者在标准库中定义

str 是唯一定义在 Rust 语言特性中的字符串,但也是几乎不会用到的字符串类型
str 字符串是 DST 动态大小类型,编译器无法在编译期知道 str 类型的大小,只有到了运行期才能动态获知
这对于强类型、强安全的 Rust 语言来说不可接受

let string: str = "banana";

创建一个 str 类型的字符串,编译会报错:

error[E0277]: the size for values of type `str` cannot be known at compilation time--> src/main.rs:4:9|
4 |     let string: str = "banana";|         ^^^^^^ doesn't have a size known at compile-time

原因:
所有的切片都是动态类型,无法直接被使用,str 是字符串切片,[u8] 是数组切片
str 是 String 和 &str 的底层数据类型

String

str 类型是硬编码进可执行文件,无法被修改
String 是一个可增长、可改变且具有所有权的 UTF-8 编码的字符串
Rust 提到字符串时,往往指的是 String 类型和 &str 字符串切片类型,这两个类型都是 UTF-8 编码

示例

在这里插入图片描述
在这里插入图片描述

其他

Rust 的标准库还提供了其他类型的字符串,例如 OsString, OsStr, CsString 和 CsStr 等
这些名字都以 String 或者 Str 结尾,它们分别对应的是具有所有权和被借用的变量

具体区分

String

类型本质:String 是一个可变的、拥有所有权的字符串类型,存储在堆上,并且可以动态增长
内存管理:由 Rust 的所有权系统管理,当 String 离开作用域时,其占用的内存会被自动释放
使用场景:当需要对字符串进行修改(如追加、删除字符)时使用

fn main() {let mut s = String::from("hello");s.push_str(", world!");println!("{}", s);
}

str

类型本质:str 是一个不可变的、无固定大小的字符串切片类型,通常被称为 “字符串切片”。没有所有权,只是对存储在其他地方的字符串数据的引用
内存管理:由于 str 是无固定大小的类型,不能直接使用,通常以引用的形式 &str 出现
使用场景:用于表示一个字符串的一部分,如字符串的子串

&str

类型本质:&str 是对 str 类型的引用,是一个不可变的字符串切片。它指向一个连续的 UTF - 8 编码的字节序列
内存管理:是一个借用类型,不拥有底层数据的所有权,只要借用的对象存在,&str 就有效
使用场景:当只需要读取字符串内容而不需要修改它时,使用 &str 作为函数参数可以接受多种字符串类型(如 String 和字面量字符串)

fn print_string(s: &str) {println!("{}", s);
}fn main() {let s1 = String::from("hello");print_string(&s1);print_string("world");
}

&String

类型本质:&String 是对 String 类型的引用
内存管理:是一个借用类型,不拥有 String 的所有权,只要 String 对象存在,&String 就有效
使用场景:通常在已经有 String 类型的变量,而函数参数要求引用时使用

fn print_string_ref(s: &String) {println!("{}", s);
}fn main() {let s = String::from("hello");print_string_ref(&s);
}

Box<str>

类型本质:Box<str> 是将 str 类型装箱到堆上的类型。它拥有底层 str 的所有权
内存管理:当 Box<str> 离开作用域时,底层的 str 数据会被自动释放
使用场景:当需要在堆上存储 str 数据,并且希望拥有其所有权时使用

fn main() {let s: Box<str> = "hello".into();println!("{}", s);
}

Box<&str>

类型本质:Box<&str> 不是一个常见用法,&str 本身是引用类型,将其装箱没意义。Box<&str> 会在堆上存储一个 &str 引用
内存管理:Box<&str> 拥有这个引用的所有权,但引用指向的数据本身的生命周期需要单独管理
使用场景:一般不建议使用,容易造成混淆

OsString 和 OsStr

类型本质:OsString 是一个拥有所有权的字符串类型,用于表示操作系统相关的字符串,如文件路径。OsStr 是 OsString 的不可变视图,类似于 str 是 String 的不可变视图
内存管理:OsString 管理自己的内存,OsStr 是借用类型
使用场景:在处理与操作系统交互的字符串时使用,如文件系统操作

use std::ffi::OsString;
use std::path::PathBuf;fn main() {let os_string = OsString::from("example.txt");let path = PathBuf::from(os_string);println!("{:?}", path);
}

注意:OsString 和 String 的内存管理不一样

CsString 和 CsStr

类型本质:CsString 和 CsStr 是 cstr_core crate 中的类型,用于处理以空字符结尾的 C 风格字符串。CsString 拥有字符串数据,CsStr 是不可变视图
内存管理:CsString 管理自己的内存,CsStr 是借用类型
使用场景:在与 C 代码进行交互时,需要处理 C 风格字符串时使用

use cstr_core::CStr;
use std::ffi::CString;fn main() {let c_string = CString::new("hello").unwrap();let c_str = c_string.as_c_str();println!("{:?}", c_str);
}

注意:CsString 和 String 的内存管理不一样

如何查看字符串的大小

String

fn main() {// String 内部是以 UTF - 8 字节序列存储// String 是 Rust 标准库中用于表示可增长、拥有所有权的 UTF - 8 编码字符串的类型let s = String::from("Hello, 世界");// 获取字节长度let byte_length = s.len();// 13println!("Byte length: {}", byte_length);// 获取字符数量let char_count = s.chars().count();// 9println!("Character count: {}", char_count);
}

CsString

use cstr_core::CString;fn main() {let cs_string = CString::new("Hello, C-style").expect("Failed to create CString");// 获取不包含空字符的字节长度let byte_length_without_nul = cs_string.as_c_str().to_bytes().len();// 14println!("Byte length without null terminator: {}", byte_length_without_nul);// 获取包含空字符的字节长度let byte_length_with_nul = cs_string.as_c_str().to_bytes_with_nul().len();// 15println!("Byte length with null terminator: {}", byte_length_with_nul);
}

OsString

可以将 OsString 转换为 OsStr,然后根据操作系统的编码方式将其转换为 &str 或字节切片来获取长度

use std::ffi::OsString;fn main() {let os_string = OsString::from("Hello, OS");// 尝试将 OsString 转换为 &str 并获取长度if let Some(s) = os_string.to_str() {let byte_length = s.len();// 9println!("Byte length: {}", byte_length);}
}

在上述代码中,os_string.to_str() 尝试将 OsString 转换为 &str,如果转换成功,则可以使用 len() 方法获取其字节长度。需要注意的是,to_str() 可能会失败,因为 OsString 可能包含非 UTF - 8 编码的数据。如果需要处理非 UTF - 8 数据,可以使用 os_string.into_vec() 方法将其转换为字节向量,然后获取向量的长度。
综上所述,不同类型的字符串获取长度的方法有所不同,需要根据具体类型和需求选择合适的方法。

std::ffi::OsString的os_string.to_str()

pub fn to_str(&self) -> Option<&str>

&OsString转为Option<&str>

pub trait Deref {type Target: ?Sized;// Required methodfn deref(&self) -> &Self::Target;
}// 
impl ops::Deref for OsString {type Target = OsStr;#[inline]fn deref(&self) -> &OsStr {&self[..]}
}

to_str() 是 OsStr 类型的一个方法,OsString 可以通过自动解引用转换为 OsStr 来调用这个方法。
to_str() 方法的作用是尝试将 OsStr 转换为 &str
它的实现原理是检查 OsStr 内部存储的字节序列是否是有效的 UTF - 8 编码。如果是有效的 UTF - 8 编码,就返回一个 Some(&str);如果不是有效的 UTF - 8 编码,则返回 None

Deref 机制主要用于在需要某个类型的引用时,自动将一个类型的引用转换为另一个类型的引用。
String 实现了 Deref<Target = str>,意味着当有一个 &String 类型的变量时,Rust 会自动将其转换为 &str,以便可以调用 str 类型的方法。

os_string.to_str() 并不是依赖 Deref 来完成从 OsString 到 &str 的转换。它是通过检查 OsStr 内部字节序列的 UTF - 8 有效性来进行转换的。

自动解引用

以 OsString 转换 OsStr 为例
在 Rust 中,OsString 可以自动解引用转换为 OsStr,这种转换主要发生在以下几种场景:

调用 OsStr 方法时

当调用一个 OsStr 类型的方法,而实际操作的是 OsString 实例时,Rust 会自动进行解引用转换。
这是因为 OsString 实现了 Deref<Target = OsStr> 特征,该特征允许 Rust 在需要 OsStr 引用的地方使用 OsString 引用

use std::ffi::OsString;fn main() {let os_string = OsString::from("example.txt");// 调用 OsStr 的 to_str 方法,这里自动将 OsString 转换为 OsStrif let Some(s) = os_string.to_str() {println!("Converted to &str: {}", s);}
}

在上述代码中,os_string 是 OsString 类型,但 to_str 是 OsStr 类型的方法

作为函数参数传递时

当一个函数的参数类型是 &OsStr,而传递的是 &OsString 时,Rust 会自动进行解引用转换。

use std::ffi::{OsStr, OsString};fn print_os_str(os_str: &OsStr) {if let Some(s) = os_str.to_str() {println!("{}", s);}
}fn main() {let os_string = OsString::from("test.txt");// 自动将 &OsString 转换为 &OsStr 传递给函数print_os_str(&os_string);
}

赋值给 &OsStr 类型变量时

当将一个 &OsString 赋值给一个 &OsStrc类型的变量时,也会发生自动解引用转换。

use std::ffi::OsString;fn main() {let os_string = OsString::from("file.txt");// 自动将 &OsString 转换为 &OsStrlet os_str: &OsStr = &os_string;if let Some(s) = os_str.to_str() {println!("{}", s);}
}

这里,&os_string&OsString 类型,而 os_str 是 &OsStr 类型,Rust 会自动完成转换。

既然可以通过Defef自动转换,那还要as_os_str干嘛

pub fn as_os_str(&self) -> &OsStr

显式表达意图

代码的可读性和可维护性在软件开发中至关重要。使用 as_os_str 方法可以更清晰地表达想要将 OsString 转换为 &OsStr 的意图。相比自动解引用,显式调用方法能让阅读代码的人一眼就明白正在进行类型转换操作。

use std::ffi::OsString;fn main() {let os_string = OsString::from("example.txt");// 显式转换,意图清晰let os_str = os_string.as_os_str(); if let Some(s) = os_str.to_str() {println!("{}", s);}
}

避免潜在的混淆

在某些复杂的代码场景中,自动解引用可能会导致代码的行为变得难以理解。自动解引用是 Rust 编译器在背后自动完成的,当代码中有多个类型实现了 Deref 特征时,可能会引发混淆。使用 as_os_str 可以避免这种潜在的混淆,让代码的行为更加明确。

与其他类型转换保持一致性

在 Rust 标准库中,很多类型都提供了显式的类型转换方法,比如 String 有 as_str 方法用于转换为 &strVec<T> 有 as_slice 方法用于转换为 &[T]。OsString 的 as_os_str 方法与这些设计保持一致,使得代码的风格更加统一。

代码审查和调试

在代码审查过程中,显式的类型转换方法更容易被审查人员识别和理解。同时,在调试代码时,显式调用方法可以让调试者更清楚地看到类型转换的位置和过程,有助于快速定位问题。

总结

尽管 Deref 自动转换提供了便利,但 as_os_str 方法通过显式表达意图、避免混淆、保持一致性以及方便代码审查和调试等方面,为代码的质量和可维护性提供了保障。

相关文章:

Rust~String、str、str、String、Box<str> 或 Box<str>

Rust语言圣经中定义 str Rust 语言类型大致分为两种&#xff1a;基本类型和标准库类型&#xff0c;前者由语言特性直接提供&#xff0c;后者在标准库中定义 str 是唯一定义在 Rust 语言特性中的字符串&#xff0c;但也是几乎不会用到的字符串类型 str 字符串是 DST 动态大小…...

SpringBoot五:JSR303校验

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 松散绑定 意思是比如在yaml中写的是last-name&#xff0c;这个和lastName意思是一样的&#xff0c;-后的字母默认是大写的 JSR303校验 就是可以在字段增加…...

Oracle 数据库基础入门(四):分组与联表查询的深度探索(上)

在 Oracle 数据库的学习进程中&#xff0c;分组查询与联表查询是进阶阶段的重要知识点&#xff0c;它们如同数据库操作的魔法棒&#xff0c;能够从复杂的数据中挖掘出有价值的信息。对于 Java 全栈开发者而言&#xff0c;掌握这些技能不仅有助于高效地处理数据库数据&#xff0…...

基于SpringBoot的绿城郑州爱心公益网站设计与实现现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

创建一个简单的spring boot+vue前后端分离项目

一、环境准备 此次实验需要的环境&#xff1a; jdk、maven、nvm和node.js 开发工具&#xff1a;idea或者Spring Tool Suite 4&#xff0c;前端可使用HBuilder X&#xff0c;数据库Mysql 下面提供maven安装与配置步骤和nvm安装与配置步骤&#xff1a; 1、maven安装与配置 1…...

标签使用笔记

文章目录 文件夹结构可以有多个功能吗?标签是如何保存的 标签做成对外接口保存、修改查询删除标签列表标签表设计标签和分类的区别 虽然大体知道怎么设计做&#xff0c;但是整理出来更清晰&#xff0c;那么整理下。 一般来说有两种索引就够。 1、标题文字索引。 # 用于搜索文章…...

Unity图集使用事项

一. 图集布局算法 紧密填充是一种常见的图集布局算法&#xff0c;它的主要目标是尽可能地减少图集的空间浪费。该算法会根据图像的形状和大小&#xff0c;将它们紧密地排列在图集中&#xff0c;以确保最小化空白区域的存在。这样可以有效地利用内存&#xff0c;并减少图集的尺…...

Flutter 学习之旅 之 flutter 在 Android 端读取相册图片显示

Flutter 学习之旅 之 flutter 在 Android 端读取相册图片显示 目录 Flutter 学习之旅 之 flutter 在 Android 端读取相册图片显示 一、简单介绍 二、简单介绍 image_picker 三、安装 image_picker 四、简单案例实现 五、关键代码 代码说明&#xff1a; 一、简单介绍 Fl…...

RagFlow专题二、RagFlow 核心架构(数据检索、语义搜索与知识融合)

深入解析 RagFlow 核心架构:数据检索、语义搜索与知识融合 在前一篇文章中,我们对 RagFlow 的核心理念、与传统 RAG 的区别以及其适用场景进行了深入探讨。我们了解到,RagFlow 通过动态优化检索、增强生成质量以及实时知识管理,使得大模型在复杂任务中的表现更加稳定和高效…...

解决各大浏览器中http地址无权限调用麦克风摄像头问题(包括谷歌,Edge,360,火狐)后续会陆续补充

项目场景&#xff1a; 在各大浏览器中http地址调用电脑麦克风摄像头会没有权限&#xff0c;http协议无法使用多媒体设备 原因分析&#xff1a; 为了用户的隐私安全&#xff0c;http协议无法使用多媒体设备。因为像摄像头和麦克风属于可能涉及重大隐私问题的API&#xff0c;ge…...

【SpringBoot+Vue】博客项目开发二:用户登录注册模块

后端用户模块开发 制定参数交互约束 当前&#xff0c;我们使用MybatisX工具快速生成的代码中&#xff0c;包含了一个实体类&#xff0c;这个类中包含我们数据表中的所有字段。 但因为有些字段&#xff0c;是不应该返回到前端的&#xff0c;比如用户密码&#xff0c;或者前端传…...

(十 二)趣学设计模式 之 享元模式!

目录 一、 啥是享元模式&#xff1f;二、 为什么要用享元模式&#xff1f;三、 享元模式的实现方式四、 享元模式的优缺点五、 享元模式的应用场景六、 总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜欢博主的讲解方式&#xff0c;可以多多支…...

leetcode第77题组合

原题出于leetcode第77题https://leetcode.cn/problems/combinations/ 1.树型结构 2.回溯三部曲 递归函数的参数和返回值 确定终止条件 单层递归逻辑 3.代码 二维数组result 一维数组path void backtracking(n,k,startindex){if(path.sizek){result.append(path);return ;}…...

Linux | Ubuntu 与 Windows 双系统安装 / 高频故障 / UEFI 安全引导禁用

注&#xff1a;本文为 “buntu 与 Windows 双系统及高频故障解决” 相关文章合辑。 英文引文&#xff0c;机翻未校。 How to install Ubuntu 20.04 and dual boot alongside Windows 10 如何将 Ubuntu 20.04 和双启动与 Windows 10 一起安装 Dave’s RoboShack Published in…...

Docker入门指南:Windows下docker配置镜像源加速下载

Windows下docker配置镜像源加速下载 docker的官方镜像是海外仓库&#xff0c;默认下载耗时较长&#xff0c;而且经常出现断站的现象&#xff0c;因此需要配置国内镜像源。 国内镜像源概述 国内现有如下镜像源可以使用 "http://hub-mirror.c.163.com", "http…...

web前端基础修炼手册

目录 引言 1. 安装插件 2. 前端三剑客 3. 开发者模式 第一章 HTML 1.文件结构 2. 常见标签 2.1 注释标签 2.2 标题标签 2.3 段落标签 2.4 换行标签 2.5 格式化标签 2.6 图片标签 2.7 超链接标签 2.8 表格标签 2.9 列表标签 2.10 form标签 2.11 input 标签 2.12 la…...

【无标题】Ubuntu22.04编译视觉十四讲slambook2 ch4时fmt库的报错

Ubuntu22.04编译视觉十四讲slambook2 ch4时fmt库的报错 cmake ..顺利&#xff0c;make后出现如下报错&#xff1a; in function std::make_unsigned<int>::type fmt::v8::detail::to_unsigned<int>(int): trajectoryError.cpp:(.text._ZN3fmt2v86detail11to_unsi…...

macos下myslq图形化工具之Sequel Ace

什么是Sequel Ace 官方github&#xff1a;https://github.com/Sequel-Ace/Sequel-Ace Sequel Ace 是一款快速、易于使用的 Mac 数据库管理应用程序&#xff0c;用于处理 MySQL 和 MariaDB 数据库。 Sequel Ace 是一款开源项目&#xff0c;采用 MIT 许可证。用户可以通过 Ope…...

【AHK】资源管理器自动化办公实例/自动连点设置

此处为一个自动连续点击打开检查的自动化操作案例&#xff0c;没有quicker的鼠键录制&#xff0c;不常用了&#xff0c;做个备份 #MaxThreadsPerHotkey 2 ; 这个是核心&#xff01;&#xff01;&#xff01;&#xff01;确保可以同时运行多个热键或标签global isRunning : tru…...

通用查询类接口数据更新的另类实现

文章目录 一、简要概述二、java工程实现1. 定义main方法2. 测试运行3. 源码放送 一、简要概述 我们在通用查询类接口开发的另类思路中&#xff0c;关于接口数据的更新&#xff0c;提出了两种方案&#xff1a; 文件监听 #mermaid-svg-oJQjD6jQ8T19XlHA {font-family:"tre…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...