Rust 中的字符是 Unicode 类型,因此每个字符占据 4 个字节内存空间,但字符串不一样,字符串是 UTF-8 编码,也就是字符串中的字符所占的字节数是变化的(1 - 4)。
常见的字符串有两种:
- str,通常是引用类型,
&str
,即字符串字面常量,字符串切片。 - std::string::String
类型&str
的变量是被硬编码的,快速而高效,但不可变;类型String
,是可设可变的,它是在堆上的变量,如何管理内存,有的语言用垃圾回收机制(Garbage Collection),标记使用情况并自动清理;而Rust不愿意用GC,既要高性能,又要高安全性,提出变量离开作用域即自动释放其占用的内存,比GC思路更妙。
C语言中清理内存的函数free,要被手动调用;Rust中则是drop(),Rust自动调用。
C++中的Resoure Acquisition Is Initialization,RAII模型。
两种字符串类型互转
&str
转String
:
let a = String::from("hello, world");
"hello, world".to_string();
String
转&str
,引用即可
fn main() {
let s = String::from("hello,world!");
say_hello(&s);
say_hello(&s[..]);
say_hello(s.as_str());
}
fn say_hello(s: &str) {
println!("{}",s);
}
除上述两种类型,Rust标准库还有其他类型的字符串。
字符串不能被直接索引
Rust字符串不允许索引操作。由于不同字符占用字节数不等,考虑操作时间复杂度不能实现O(1)。
//三个字节
let a = "中国人";
//一个字节
let b = "Chinese";
Rust字符串虽然不能索引但可以切片(slice),类似Python等语言中的切片概念。
fn main() {
let my_name = "kirk zhang";
let first_name = &my_name[0..4];
let last_name = &my_name[5..10];
println!("{}",first_name);
println!("{}",last_name);
greet(String::from(my_name));
// 尝试my_name[0]报错,不过可以用.chars().nth或.bytes()来实现
println!("can str be indexed {:?}",my_name.chars().nth(0));
}
fn greet(name: String){
println!("hello {}", name);
}
小心字符串切片
注意字符串切片是按字节来的哦,而Rust字符串是UTF-8协议格式,一般1个字符1个字节,但1个中文字符占3个字节;如果切片起止不在字符边界,则有异常。
fn main(){
let f = "中国人";
let f1 = &f[0..5];
println!("watch out, what you got {}",f1);
}
提示:thread ‘main’ panicked at ‘byte index 5 is not a char boundary; it is inside ‘国’ (bytes 3…6) of 中国人
’, src/main.rs:10:15
note: run with RUST_BACKTRACE=1
environment variable to display a backtrace
字符串的操作
替换
replace(要被替换的子串,新字符串),返回结果字符串。
let word = String::from("rust");
let new_word = word.replace("r","R");
println!("{}", new_word);
插入
insert(位置索引,字符)、insert_str(位置索引,字符串):变量本身变化,声明时要mut。
let word = String::from("rust");
let mut new_word = word.replace("r","R");
new_word.insert_str(0, "I love ");
println!("{}", new_word);
追加
push(字符)
push_str(字符串)
let word = String::from("rust");
let mut new_word = word.replace("r","R");
new_word.insert_str(0, "I love ");
new_word.push('!');
println!("{}", new_word);
连接
+
或+=
调用了String的add(self,&str)
方法,其定义要求+后面的参数为字符串字面常量,返回String类型。
或用format! ,适用于 String 和 &str 。format! 的用法与 println! 的用法类似。
let a1 = String::from("tic");
let a2 = String::from("tac");
let a3 = String::from("toe");
// 经过下面一行后,a1被释放了,不能再使用!a2、a3依然存在。
let s = s1 + "-" + &s2 + "-" + &s3;
删除
有4个方法,pop()、remove(索引位置)、truncate(起始位置)、clear()
注意删除字符串的索引必须是字符串中字符的边界,否则错误。文章来源:https://www.toymoban.com/news/detail-829519.html
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);
}
字符串的字符与字节
例,文章来源地址https://www.toymoban.com/news/detail-829519.html
for c in "中国人".chars() {
println!("{}", c);
}
for b in "中国人".bytes() {
println!("{}", b);
}
到了这里,关于【编程】Rust语言入门第4篇 字符串的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!