跳至主要內容

02-字符串

黑静美原创...大约 5 分钟编程rust

本文内容摘编自: 快速入门:Rust中有哪些你不得不了解的基础语法?open in new window(著作权归AI悦创所有) Rust语言圣经(Rust Course)-字符串与切片open in new window

字符串

x = " "

Rust 字符串对 Unicode 字符集有着良好的支持

let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
let hello = String::from("你好");

&str 本质是一种切片Slice。切片详见 切片与引用。其中字符也由UTF-8编码。它既单独输出一些内容,也可以截取String中的内容。

  • 语法
 let hello = ""

或者截取

let s = String::from("可爱的人");
let slice = &s[0..2];

__

提示

注意,Rust 中的String不能通过下标(索引)去访问。

let hello = String::from("你好");
// let a = hello[0];  // 你可能想把“你”字取出来,但实际上这样是错误的

该代码会产生如下错误:

3 |     let h = hello[0];
  |             ^^^^^^^^ `String` cannot be indexed by `{integer}`
  |
  = help: the trait `Index<{integer}>` is not implemented for `String`

因为 String 存储的 Unicode 序列的 UTF-8 编码,而 UTF-8 编码是变长编码

UTF-8为何是变长编码[Ref2]open in new window

  • 拉丁字母

    对于 let hello = String::from("Hola"); 这行代码来说,Hola 的长度是 4 个字节,因为 "Hola" 中的每个字母在 UTF-8 编码中仅占用 1 个字节,但是对于下面的代码呢?

  • 中文
let s = String::from("中国人");

该字符串是 9 个字节的长度,因为大部分常用汉字在 UTF-8 中的长度是 3 个字节。

224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135

长度是 18 个字节,这也是计算机最终存储该字符串的形式。如果从字符的形式去看,则是:

'न', 'म', 'स', '्', 'त', 'े'

但是书写过程中,第四和六两个字母根本就不存在,在这种语言中只是两个辅助值并不占位。接着再从字母串的形式去看:

["न", "म", "स्", "ते"]

所以,可以看出来 Rust 提供了不同的字符串展现方式,这样程序可以挑选自己想要的方式去使用,而无需去管字符串从人类语言角度看长什么样。

还有一个原因导致了 Rust 不允许去索引字符串:因为索引操作,我们总是期望它的性能表现是 O(1),然而对于 String 类型来说,无法保证这一点,因为 Rust 可能需要从 0 开始去遍历字符串来定位合法的字符。

强行采用&s[]取值

如果你想从索引 0 开始,可以使用如下的方式,这两个是等效的:

fn main() {
    let s = String::from("中国人");
    let _slice = &s[0..3];
    let _slice = &s[..3];
    println!("{}",_slice);

}

::: dinger

错误示例:

let s = String::from("中国人");
// let a = &s[0..2];
// println!("{}",a);

:::

这种情况下对 s 进行索引,访问 &s[0..1] 没有任何意义,因为我们只取 s 字符串的前两个字节,但是本例中每个汉字占用3个字节,因此没有落在边界处,也就是连 字都取不完整,这是一个非常奇怪而且难以理解的返回值。此时程序会直接崩溃退出。

如果改成 &s[0..3],则可以正常通过编译。 因此,当你需要对字符串做切片索引操作时,需要格外小心这一点。


字符串的转义

与 C 语言一样,Rust 中转义符号也是反斜杠 \ ,可用来转义各种字符。

fn main() {
    /* 将""号进行转义 */
    let byte_escape = "I'm saying \"Hello\"";
    println!("{}", byte_escape);
    
    /* 分两行打印(转义换行符) */
    let byte_escape = "I'm saying \n 你好";
    println!("{}", byte_escape);
    
    /* Windows下的换行符 */
    let byte_escape = "I'm saying \r\n 你好";
    println!("{}", byte_escape);
    
    /* 打印出 \ 本身 */
    let byte_escape = "I'm saying \\ Ok";
    println!("{}", byte_escape);
    
    /* 强行在字符串后面加个0,与C语言的字符串一致。*/
    let byte_escape = "I'm saying hello.\0";
    println!("{}", byte_escape);
}

除此之外,Rust 还支持通过 \x 输入等值的 ASCII 字符,以及通过 \u{} 输入等值的 Unicode 字符。

fn main() {
    // 使用 \x 输入等值的ASCII字符(最高7位)
    let byte_escape = "I'm saying hello \x7f";
    println!("{}", byte_escape);
    
    // 使用 \u{} 输入等值的Unicode字符(最高24位)
    let byte_escape = "I'm saying hello \u{0065}";
    println!("{}", byte_escape);
}
不转义字符串

有时候,我们不希望字符串被转义,也就是想输出原始字面量。这个在 Rust 中也有办法,使用 r""r#""# 把字符串字面量套起来就行了。

fn main() {
    // 字符串字面量前面加r,表示不转义
    let raw_str = r"Escapes don't work here: \x3F \u{211D}";
    println!("{}", raw_str);
    
    // 这个字面量必须使用r##这种形式,因为我们希望在字符串字面量里面保留""
    let quotes = r#"And then I said: "There is no escape!""#;
    println!("{}", quotes);
    
    // 如果遇到字面量里面有#号的情况,可以在r后面,加任意多的前后配对的#号,
    // 只要能帮助Rust编译器识别就行
    let longer_delimiter = r###"A string with "# in it. And even "##!"###;
    println!("{}", longer_delimiter);
}

一点小提示,Rust 中的字符串字面量都支持换行写,默认把换行符包含进去。

注:字符串转义的详细知识点,请参考 Tokens - The Rust Reference (rust-lang.org)open in new window

在Rust中,标准输入的读取通常是通过 io::stdin().read_line() 实现的。如果你想要一种更简便的方式,尤其是对于需要从命令行读取单个值的场景,可以使用第三方的库,比如 text_ioclap 来简化输入。

这里是一个使用 text_io 库的示例,它可以简化用户输入的读取过程:

使用 text_io

首先,你需要在 Cargo.toml 文件中添加 text_io 作为依赖项:

[dependencies]
text_io = "0.1"

然后,你可以使用以下代码来简化输入过程:

use text_io::read;

fn main() {
    println!("Enter value: ");
    let input: f32 = read!();

    let fahrenheit = (input * 1.8) + 32.0;

    println!("{:.2}°C = {:.2}°F", input, fahrenheit);
}

这个示例中,read!() 宏会自动从标准输入读取并解析值,使代码更加简洁。

上次编辑于:
贡献者: Heijingmei
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3