30天拿下Rust之字符串

这篇具有很好参考价值的文章主要介绍了30天拿下Rust之字符串。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

        在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:&str和String。其中,&str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实体。

&str和String

        &str和String是Rust中两种主要的字符串类型,它们在以下6个方面存在比较明显的区别。

        所有权和可变性

        &str:是Rust核心语言中唯一的字符串类型,它是一个不可变的字符串切片,是对字符串数据的引用,并不拥有数据的所有权。&str可以安全地使用,但它的内容是不可变的,也就是说,不能改变它指向的字符串的内容。&str可以指向String的内容,也可以指向静态字符串字面量。

        String:这是一个在堆上分配的、可变的字符串类型。String类型由Rust标准库提供,而不是编入核心语言。它拥有其内容的所有权,这意味着String可以被修改。String本质上是一个封装了动态大小数组(Vec<u8>)的结构体,该数组存储了UTF-8编码的字节。

        生命周期

        &str:生命周期取决于它的来源。如果是字符串字面量,则生命周期为'static。如果来自某个作用域内的String或其他类型,则其生命周期与该作用域相同。

        String:没有明确的生命周期限制,只要String实例存在,它就可以被使用。

        存储位置

        &str:可能是指向静态内存中的字符串字面量(&'static str),比如:编译时确定的常量字符串。也可能是指向堆上分配的String的一部分,或者任何其他类型的UTF-8编码数据的区域。

        String:始终在堆上动态分配。

        性能

        &str:由于它只是一个引用,没有额外的内存分配成本,因此在某些情况下可能更高效。

        String:由于它在堆上分配,因此会有额外的内存分配和复制成本,尤其是在字符串拼接时。

        使用场景

        &str:当只需要读取字符串内容,或者想要避免额外的内存分配时,使用&str。此外,在函数参数中,使用&str可以允许函数接受不同类型的字符串参数,包括:String和静态字符串字面量。

        String:当需要一个可变的字符串,或者不关心字符串的具体来源时,使用String。

        与C/C++语言的比较

        &str:类似于C语言中的const char *,它只是一个指向字符串数据的指针,并不拥有数据。在Rust中,&str比C语言中的裸指针更安全,因为它有一个生命周期参数来确保引用的有效性。

        String:类似于C++中的std::string,是一个字符的容器,并且拥有其内容。

字符串的创建

        在Rust中,创建字符串有多种方法。根据具体需求,我们可以选择不同的方法。如果需要一个可变的字符串并且打算在程序运行时修改它,那么String类型是最佳选择。如果只是需要一个对静态文本的引用,那么&str就足够了。

        使用字符串字面量创建&str

        字符串字面量是在代码中直接写入的文本,它们被存储在程序的只读数据段中,并且是不可变的。字符串字面量隐式地具有&str类型。在下面的示例代码中,text是一个指向字符串字面量的引用,其类型为&str。

let text: &str = "Hello, CSDN";

        使用String::new创建空的String

        如果我们想要一个可变的、可以增长的字符串,应该使用String类型。在下面的示例代码中,empty_str是一个空的String变量,我们可以向其中添加内容。

fn main() {
    let mut empty_str = String::new();
    empty_str.push_str("Hello");
    println!("{}", empty_str);
}

        使用字符串字面量初始化String

        可以直接将字符串字面量转换为String,这是通过调用to_string方法或to_owned方法来实现的。

fn main() {
    let text1 = "Hello, CSDN".to_string();
    let str_slice: &str = "Hello, Rust";
    let text2 = str_slice.to_owned();
    println!("{}", text1);
    println!("{}", text2);
}

        使用format!宏创建String

        format!宏是Rust中创建格式化字符串的强大工具,它可以根据提供的格式字符串和参数生成一个 String。

fn main() {
    let name: &str = "CSDN";
    let info = format!("Hello, {}", name);
    println!("{}", info);
}

        使用String::from创建String

        String::from是一个便利的方法,用于从实现了Into<String>特征的任何类型创建String。因为字符串字面量隐式地实现了这个特征,故可以直接使用。

let text = String::from("Hello, CSDN");

字符串的拼接

        Rust提供了强大的字符串拼接功能,可以让字符串操作变得更加灵活和高效。

        使用+运算符或+=运算符

        如果想要将两个String类型进行拼接,可以使用+运算法。

fn main() {
    let str1 = String::from("Hello");
    let str2 = String::from(" CSDN");
    // 不能直接使用str1 + str2
    let str = str1 + &str2;
    println!("{}", str);
    // 编译错误:value borrowed here after move
    println!("{}", str1);
}

        在上面的示例代码中,我们将str1和str2进行了拼接,并得到了str。拼接时,我们使用了&str2,而没有直接使用str2。拼接完成后,str1不再有效。之所以会这样,与使用+运算符时调用的函数签名有关。Rust的+运算符使用了add函数,其签名与下面的函数声明类似。

fn add(self, s: &str) -> String

        首先,str2使用了&,意味着我们使用第二个字符串的引用与第一个字符串相加。这是因为add函数只能将&str和String相加,而不能将两个String值相加。在Rust中,可以通过Deref强制转换将&String强转成&str,相当于自动把&str2变成了&str2[..]。其次,add函数直接获取了self的所有权,因为self没有使用&。这意味着,str1的所有权被移动到add函数后,str1将不再有效。

        若要对可变的String进行拼接操作,还可以使用+=操作符。但实际上,这并不是简单的连接,而是创建了一个新的String实例,并丢弃了原String分配的内存。

fn main() {
    let mut str1 = String::from("Hello");
    let str2 = " CSDN";
    str1 += str2;
    println!("{}", str1);
}

        注意:使用+=运算符,或者连续使用+运算符进行多次拼接,会导致多次内存分配,效率较低,尤其是在处理大量数据时。如果需要高效地拼接多个字符串,建议使用下面的format!宏。

        使用format!宏

        format!宏是一种更灵活且高效的字符串拼接方法,尤其适用于包含变量和格式化文本的情况。format!宏可以处理各种复杂的格式化需求,并且它的性能通常优于简单的+拼接。

fn main() {
    let name: &str = "CSDN";
    let info = format!("Hello, {}", name);
    println!("{}", info);
}

        使用push_str方法或push方法

        如果已经有了一个String变量,并且想要将另一个字符串或字符追加到它后面,可以使用push_str方法或push方法。注意:push系列方法不会创建新的String实例,而是直接在原有的String缓冲区上追加内容,这通常比使用+运算符更高效。

fn main() {
    let mut text = String::from("Hello ");
    text.push_str("Rust");
    println!("{}", text);

    text.push(' ');
    text.push('C');
    text.push('S');
    text.push('D');
    text.push('N');
    println!("{}", text);
}

字符串的搜索与替换

        在Rust中,我们可以使用find、rfind、contains、replace等方法来进行字符串的搜索与替换。在下面的示例代码中,我们首先调用find方法查找子串"CSDN",并返回一个Option类型的值。接下来,我们调用contains方法来检查text字符串是否包含了子串"Hello",若包含,返回true,否则返回false。最后,我们调用replace方法来替换字符串中的子串。

        replace方法接收两个参数:第一个参数是要被替换的子串,第二个参数是替换后的新子串。该方法会返回一个新的字符串,其中所有与给定模式匹配的子串都被替换为指定的替换字符串。注意:第一个参数中的原始字符串不会被修改。

fn main() {
    let text = "Hello CSDN";

    // 搜索子串
    let index = text.find("CSDN");
    if let Some(value) = index {
        println!("found: {}", value);
    } else {
        println!("not found");
    }

    // 包含子串
    let contain_hello = text.contains("Hello");
    println!("contain hello: {}", contain_hello);
    
    // 替换子串
    let replaced: String = text.replace("CSDN", "GitHub");
    println!("{}", replaced);
}

字符串的长度

        在Rust中,获取字符串的长度是一个常见的操作。Rust的String类型提供了一个len方法,可以用来获取字符串中字节的数量。需要特别注意的是:这个长度是以字节为单位的,对于ASCII字符串来说,每个字符占用一个字节;但是,对于包含多字节字符(比如:UTF-8编码的Unicode字符)的字符串,len方法返回的是字节的总数,而不是字符的总数。

        如果想要获取字符串中Unicode字符的数量,我们应该使用chars方法,然后计算迭代器中元素的数量。chars方法会返回一个迭代器,该迭代器逐个产生字符串中的Unicode字符。

fn main() {
    let text = "Hello 霸都";

    // 获取字节长度
    let byte_len = text.len();
    // 输出:12
    println!("{}", byte_len);

    // 获取字符长度
    let char_len = text.chars().count();
    // 输出:8
    println!("{}", char_len);
}

        另外,Rust字符串不支持直接通过索引来访问单个字符。这是因为,UTF-8编码格式下,单个字符可能占用1到4个字节,索引操作会带来潜在的非确定性和不一致性问题。如果确实需要通过索引访问字符,可以使用chars()方法。它会返回一个迭代器,产生字符串中的每个Unicode字符。然后,我们可以使用nth方法或者其他集合方法来获取特定位置的字符。

fn main() {
    let text = "Hello 霸都";
    // 注意:索引从0开始计数
    let index = 6;
    let cur_char = text.chars().nth(index);
    // 输出:index 6: 霸
    match cur_char {
        Some(c) => println!("index {}: {}", index, c),
        None => println!("index out of bounds"),
    }
}

字符串与字节的转换

        Rust中的字符串和字节之间可以方便地进行转换,这在处理二进制数据和编解码时非常有用。

fn main() {
    let text = "Hello CSDN";

    // 字符串转字节
    let bytes = text.as_bytes();
    // 输出:[72, 101, 108, 108, 111, 32, 67, 83, 68, 78]
    println!("{:?}", bytes);
    
    // 字节转字符串
    let bytes2 = [72, 101, 108, 108, 111];
    let text2 = std::str::from_utf8(&bytes2).unwrap();
    // 输出:Hello
    println!("{}", text2);
}

总结

        由于Rust强调安全性与内存管理,它的字符串设计也体现出了这一点:不可变的&str确保了引用安全,而String则通过所有权系统保证了内存的有效管理,避免了悬垂引用和其他常见的内存错误。文章来源地址https://www.toymoban.com/news/detail-839030.html

到了这里,关于30天拿下Rust之字符串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Rust类型之字符串

    Rust 中的字符串类型是 String 。虽然字符串只是比字符多了一个“串”字,但是在Rust中这两者的存储方式完全不一样,字符串不是字符的数组, String 内部存储的是 Unicode 字符串的 UTF8 编码,而 char 直接存的是 Unicode Scalar Value 。 Rust字符串对 Unicode 字符集有着良好的支持,可以

    2024年02月02日
    浏览(50)
  • rust 字符串(String)详解

    rust中的 String ,是一个非常常用的 crate ,它的底层涉及到了rust中的所有权概念,不过这不是本章的内容,如果对rust所有权概念感兴趣的,可以查看另一篇文章:rust所有权 本文的目的还是介绍 String 的基本用法,以及有哪些常用的函数可以使用 字符串,也就是由一系列字符

    2024年02月03日
    浏览(46)
  • rust里如何判断字符串是否相等呢?

    在 Rust 中,有几种方法可以判断字符串是否相等。下面是其中几种常见的方法: 使用 == 运算符:可以直接使用 == 运算符比较两个字符串是否相等。例如: 这段代码会输出 “字符串不相等”,因为 str1 和 str2 不是相同的字符串。 2. 使用 eq 方法:字符串类型实现了 PartialEq

    2024年02月14日
    浏览(62)
  • 【编程】Rust语言入门第4篇 字符串

    Rust 中的字符是 Unicode 类型,因此每个字符占据 4 个字节内存空间,但字符串不一样,字符串是 UTF-8 编码,也就是字符串中的字符所占的字节数是变化的(1 - 4)。 常见的字符串有两种: str,通常是引用类型, str ,即字符串字面常量,字符串切片。 std::string::String 类型 str 的变

    2024年02月20日
    浏览(56)
  • Rust字符串:安全、高效和灵活的数据类型

    Rust是一种现代的系统级编程语言,以其出色的内存安全性和高性能而受到广泛关注。在Rust中,字符串是一种重要的数据类型,它具有独特的特点,使其在处理文本和字符数据时成为理想的选择。本文将深入探讨Rust字符串的特性,包括安全性、高效性和灵活性,以帮助您更好

    2024年01月19日
    浏览(53)
  • Rust中的字符串处理及相关方法详解

    在Rust中,字符串是一种非常重要的数据类型,而 String 类型则提供了对动态可变字符串的支持。本文将介绍一些常见的字符串处理方法以及相关示例代码。 在Rust中,有多种方式创建字符串,以下是一些常见的例子: push_str()方法 push_str() 方法用于将一个字符串切片附加到 S

    2024年02月19日
    浏览(35)
  • 30天拿下Rust之泛型

    概述         在Rust语言中,泛型是一种强大的工具,它允许我们编写可复用且灵活的代码。通过泛型,我们可以创建适用于多种类型的数据结构和函数,而无需为每种类型都重复编写相同的逻辑。在Rust中,泛型通过指定类型参数来实现,这些类型参数会在编译时被具体类

    2024年03月17日
    浏览(49)
  • 30天拿下Rust之引用

    概述         在Rust语言中,引用机制是其所有权系统的重要组成部分,它为开发者提供了一种既高效又安全的方式来访问和共享数据。引用可以被视为一个指向内存地址的指针,它允许我们间接地访问和操作存储在内存中的数据。与其他语言中的指针不同,Rust中的引用是

    2024年03月10日
    浏览(43)
  • 30天拿下Rust之切片

    概述         在Rust中,切片是一种非常重要的引用类型。它允许你安全地引用一段连续内存中的数据,而不需要拥有这些数据的所有权。切片不包含分配的内存空间,它仅仅是一个指向数据开始位置和长度的数据结构。切片是对数组的一个连续引用,它提供了一种方便、

    2024年03月13日
    浏览(52)
  • 30天拿下Rust之面向对象

    概述         在编程语言的世界中,Rust以其独特的内存安全、并发控制和高性能特性吸引了众多开发者。虽然Rust并非传统的面向对象编程语言(比如:C++、Java),但它依然支持并提供了一种颇具特色的面向对象编程方式,以实现类似于面向对象的编程范式。        

    2024年04月15日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包