Rust学习-字符串

字符串

Rust核心语言只有一种字符串类型:str,字符串 slice,通常以被借用的形式出现,&str。
它们是一些储存在别处的 UTF-8 编码字符串数据的引用。
比如字符串字面量被储存在程序的二进制输出中,字符串 slice 也是如此。

String 是由标准库提供,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型。

谈到 “字符串”时,通常指的是 String 和字符串 slice &str 类型。
注意:String 和字符串 slice 是两个东西,但都是 UTF-8 编码。因为UTF-8 编码可以表示任何数据。

新建

// 空String
let mut s = String::new();

// to_string 方法,用于任何实现了 Display trait 的类型,字符串字面量也实现了它
let data = "initial contents";
let s = data.to_string();
let s = "initial contents".to_string();

// String::from 函数从字符串字面量创建
let s = String::from("initial contents");

更新

// push_str 方法来附加字符串 slice
// push_str 方法采用字符串 slice,因为并不需要获取参数的所有权
let mut s = String::from("foo");
s.push_str("bar");

let mut s1 = String::from("foo");
let s2 = "bar";
// s2的所有权被剥夺
s1.push_str(s2);
// 执行如下行报错
// println!("s2 is {}", s2);

// push 方法被定义为获取一个单独的字符作为参数
let mut s = String::from("lo");
s.push('l');

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1 被移动,不能继续使用
// + 运算符使用了 add 函数
// fn add(self, s: &str) -> String
// 标准库中的 add 使用泛型定义。这里的 add 签名使用具体类型代替泛型
// add 函数的 s 参数:只能将 &str 和 String 相加,不能将两个 String 值相加
// &s2 的类型是 &String 而不是 &str。为什么还能编译呢?
// 解引用强制转换(deref coercion),&String 可以被 强转(coerced)成 &str
// 它把 &s2 变成了 &s2[..]
// add 没有获取参数的所有权,所以 s2 在这个操作后仍然是有效的 String
// self 没有 使用 &
// s1 的所有权将被移动到 add 调用中,之后就不再有效

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);

不能索引

String 是一个 Vec 的封装

let len = String::from("Здравствуйте").len(); // 24

Rust不允许索引字符串的字符的原因:
(1)索引操作预期需要常数时间 (O(1)),但对于 String,Rust 必须从开头到索引位置遍历来确定有多少有效的字符,所以不是 (O(1))
(2)一个字符串字节值的索引并不总是对应一个有效的 Unicode 标量值,为了避免返回意外的值并造成不能立刻发现的 bug,请见示例

注意:如下字符串中的首字母是西里尔字母的 Ze,而不是阿拉伯数字 3

fn main() {
    let hello = "Здравствуйте";
    println!("hello={}", hello);
    println!("the first data {}", &hello[0]);
}

// the type `str` cannot be indexed by `{integer}`
// you can use `.chars().nth()` or `.bytes().nth()`

改为如下:

fn main() {
    let hello = "Здравствуйте";
    println!("hello={}", hello);
    println!("the first char {:?}", hello.chars().nth(0));
    println!("the first byte {:?}", hello.bytes().nth(0));
}
// 当使用 UTF-8 编码时,З 的第一个字节 208,第二个是 151
// 208 自身并不是一个有效的字母
// the first char Some('З')
// the first byte Some(208)

字符串 slice

使用 [] 和一个 range 来创建含特定字节的字符串 slice

let hello = "Здравствуйте";
let s = &hello[0..4]; // s是一个&str, “Зд”

// 如下panic
// &hello[0..1]

字符串的遍历

有效的 Unicode 标量值可能会由不止一个字节组成

// 操作单独的 Unicode 标量值
for c in "नमस्ते".chars() {
    println!("{}", c);
}
// 返回每一个原始字节
for b in "नमस्ते".bytes() {
    println!("{}", b);
}

附录

UTF-8 可以表示所有可打印的 ASCII 字符,以及不可打印的字符
UTF-8 还包括各种额外的国际字符,如中文字符和阿拉伯字符
UTF-8 表示字符时,每个代码都由一个或多个字节的序列来表示
(1)(0-127)ASCII 范围内的代码由一个字节表示
(2)(128-2047) 范围内的码位由两个字节表示
(3)(2048-65535) 范围内的代码点由三个字节表示
(4)(65536-1114111) 范围内的代码由四个字节表示

你可能感兴趣的:(rust,rust,学习)