Rust 字符串 初步了解

2024-01-07 17:31:02

rust 的字符串 。字符串不是复合类型,

String&str

  • String 具有所有权,是存储在堆上的。
  • &str 没有所有权,是对 String 的引用。字符串字面量也是 &str 类型,存储在栈上。

切片(slice)

对于字符串而言,切片就是对字符串一部分的引用。

let s = String::from("hello");

let s1 = &s[0..5]; // 不包含终止索引 hello

创建切片的语法:[开始索引..终止索引]。(该语法是一个右半开区间) 。
切片数据结构:保存开始的位置(指针)和切片的长度。

.. range 序列 语法。

包含第一个字节或最后一个字节时,开始索引或最后索引可以省略。

let s = String::from("hello");

let s1 = &s[..2]; // he

let s2 = &s[2..]; // llo

let s3 = &s[..]; // hello

注意
在使用切片时,需要保证索引落在字符的边界上
因为切片上的索引指的是字节,而不是字符,而且字符串使用的编码是 UTF-8
所以当一个字符占用多个字节时,索引可能不在字符的边界上,导致没有取到完成的字符,出现错误。

字符串切片的类型标识为 &str
所以切片(slice)是一个不可变引用。

其他切片

数组也可以进行切片。
切片是对集合的部分引用,所以所有是集合的类型都可以进行切片。

字符串字面量也是切片,因为类型也是 &str

字符串

字符串与字符:

  • 字符: Unicode 类型,每个字符占用 4 个字节空间。
  • 字符串: UTF-8 类型,每个字符占用的字节数是变化的(1-4).

语言级别上的字符串类型只有 str 。(编程语言提供的原生字符串类型)
标准库中,还有多种不同用途的字符串类型:用的最广的是 String 类型。(额外的字符串处理工具)

strString

  • str 类型是硬编码进可执行文件,无法被修改。
  • String 是一个可增长、可改变且具有所有权的 UTF-8 编码字符串。(&str 也是UTF-8 字符串)

String 与 &str 的转换

&strString

  • String::from("hello")
  • "hello".to_string()

String&str

  • 取引用

Rust 不允许进行字符串索引,因为索引也是按照字节的,可能会落在字符上,导致无法取到完整的字符。

操作字符串

String 的常用方法:

追加(Push)

  • push() 追加 字符
  • push_str() 追加 字符串

在用来的字符串上追加,不会返回新的字符串。
字符串必须是可变的,即必须使用 mut 修饰

let s = String::from("hello");

s.push(','); // hello,

s.push_str(" rust"); // hello, rust

插入(Insert)

  • insert() 插入单个字符 char
  • insert_str() 插入字符串字面量 &str
    需要传入两个参数:
  1. 字符(串)插入位置的索引。(从0开始计数,越界会出现错误)。
  2. 要插入的字符串。

在原来的字符串上修改,字符串必须是 可变 的,必须由 mut 关键字修饰。

fn main() {
	let mut s = String:from("hello");
	
	s.insert(5,','); // hello,
	
	s.insert_str(6," I like"); // hello, I like
}

替换(Replace)

replace

适用于 String&str 类型。

需要两个参数:

  1. 要被替换的字符串。
  2. 新的字符串。
    该方法会替换掉所有的匹配到的字符串。
    该方法返回一个新的字符串,不是操作原来的字符串
fn main() {
	let s = String::from("hello rust");
	let new_s = s.replace("rust", "RUST"); // hello RUST
}
replacen

适用于 String&str 类型。

需要三个参数:

  1. 前两个参数与 replace() 方法一样。
  2. 第三个参数表示替换的个数。
    该方法放回一个新的字符串,不是操作原来的字符串
fn main() {
	let s = String::from("hello rust rust");
	let new_s = s.replacen("rust", "RUST",1); // hello RUST rust
}
replace_range

仅适用于 String 类型。

需要两个参数:

  1. 要替换字符串的范围(Range)。
  2. 新的字符串。
    直接操作原来在字符串,不会返回新的字符串。
    需要使用 mut 关键字修饰
fn main() {
	let s = String::from("hello rust rust");
	s.replace_range(0..1,"H"); // Hello rust rust
}

删除(Delete)

1. pop —— 删除并返回字符串的最后一个字符

直接操作原来的字符串。
存在返回值,返回值是一个 Option 类型,如果字符串为空,则返回 None

fn main() {
	let mut s = String::from("hello");
	let s1 = s.pop(); // hell s1:o
	let s2 = s.pop(); // hel s2:l
}
2. remove —— 删除并返回字符串中指定位置的字符

直接操作原来的字符串。
存在返回值,返回值是删除位置的字符串。

接受一个参数:

  • 表示该字符起始索引位置。

remove() 方法按照字节处理字符串,要求所给的索引落在字符的边界位置。

fn main() {
    let mut string_remove = String::from("测试remove方法");
    println!(
        "string_remove 占 {} 个字节",
        std::mem::size_of_val(string_remove.as_str())
    );
    // 删除第一个汉字
    string_remove.remove(0);
    // 下面代码会发生错误
    // string_remove.remove(1);
    // 直接删除第二个汉字
    // string_remove.remove(3);
    dbg!(string_remove);
}
3. truncate —— 删除字符串中从指定位置到结尾的全部字符

直接操作原来的字符串。
无返回值。
truncate() 方法按照字节来处理字符串,要求参数所给的位置是合法的字符边界。

fn main() {
    let mut string_truncate = String::from("测试truncate");
    string_truncate.truncate(3); // 测
    dbg!(string_truncate);
}
4. clear —— 清空字符串

直接操作原来的字符串。
调用后,删除字符串中的所有字符。

fn main() {
    let mut string_clear = String::from("string clear");
    string_clear.clear();
    dbg!(string_clear);
}

连接(Concatenate)

1. 使用 + 或者 += 连接字符串

右边的参数必须为字符串的切片引用类型(Slice)。

调用 + 时,相当于调用了 std::string 标准库中的 add() 方法,add() 方法的第二个参数是一个引用的类型。
因此,在使用 + 时,必须传递切片引用类型,不能直接传递 String 类型

返回一个新的字符串

fn main() {
    let string_append = String::from("hello ");
    let string_rust = String::from("rust");
    // &string_rust会自动解引用为&str
    let result = string_append + &string_rust;
    let mut result = result + "!"; // `result + "!"` 中的 `result` 是不可变的
    result += "!!!";

    println!("连接字符串 + -> {}", result);
}
2. 使用 format! 连接字符串

适用于 String&str
用法与 print! 的用法类型。

fn main() {
    let s1 = "hello";
    let s2 = String::from("rust");
    let s = format!("{} {}!", s1, s2);
    println!("{}", s);
}

字符串转义

通过转义的方式 \ 输出 ASCII 和 Unicode 字符。

fn main() {
    // 通过 \ + 字符的十六进制表示,转义输出一个字符
    let byte_escape = "I'm writing \x52\x75\x73\x74!";
    println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape);

    // \u 可以输出一个 unicode 字符
    let unicode_codepoint = "\u{211D}";
    let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";

    println!(
        "Unicode character {} (U+211D) is called {}",
        unicode_codepoint, character_name
    );

    // 换行了也会保持之前的字符串格式
    // 使用\忽略换行符
    let long_string = "String literals
                        can span multiple lines.
                        The linebreak and indentation here ->\
                        <- can be escaped too!";
    println!("{}", long_string);
}

不转义的情况:

fn main() {
    println!("{}", "hello \\x52\\x75\\x73\\x74");
    let raw_str = r"Escapes don't work here: \x3F \u{211D}";
    println!("{}", raw_str);

    // 如果字符串包含双引号,可以在开头和结尾加 #
    let quotes = r#"And then I said: "There is no escape!""#;
    println!("{}", quotes);

    // 如果还是有歧义,可以继续增加,没有限制
    let longer_delimiter = r###"A string with "# in it. And even "##!"###;
    println!("{}", longer_delimiter);
}

操作 UTF-8 字符串

字符

Unicode 字符的方式遍历字符串,使用 chars 方法:

for c in "中国人".chars() {
 // c 为 字符串中的每个字符
}

字节

遍历每个字节 ,使用 bytes()

for b in "中国人".bytes() {
	// b 为 字符串的每个字节
}

获取子串

想要准确的从 UTF-8 中获取子串比较困难,标准库并没有提供对应的方法,可以使用第三方库。
推荐 库 utf8_slice

请添加图片描述
请添加图片描述

文章来源:https://blog.csdn.net/sha_mo_li/article/details/135417596
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。