一、前言
rust中的String
是一个非常常用的crate
,它的底层涉及到了rust中的所有权概念,不过这不是本章的内容,如果对rust所有权概念感兴趣的,可以查看前一篇文章:String与所有权
本文的目的是详细、全面的介绍String
的基本用法,毕竟它实在是太过常用了,自带了大量的方法。
二、基本概念
字符串,也就是由一系列字符组成的,而在计算机中存储一个字符,用到的字节数量并不完全相同。
比如下面的代码:
fn main() {
let s1=String::from("h");
let s2=String::from("你");
println!("{} {}",s1.len(),s2.len());
}
同样是一个字符,只不过s1
是英文字符,s2
是中文字符,所使用的空间就不是一样大:
1 3
一个英文字符用1
个字节大小,而一个中文字符却要用3
个字节大小。
之所以出现这个现象,是因为rust
中的字符串String
为了更加的通用化,采用的是UTF-8
编码,更多介绍可参考文章:编码。
正因为utf-8
编码的这一特性,导致了我们无法像c语言那样,可以直接遍历字符串中的所有字符:
fn main() {
let s=String::from("hello 世界");
for i in s{ //错误,无法直接遍历
}
}
同样的,你也无法直接用下标取出对应的字符
fn main() {
let s=String::from("hello 世界");
let c=s[0]; //错误,不能直接用下标取出字符
}
因为每个字符占用的内存大小不一,所以它不知道你是想要取出字符,还是想要取这个位置上的字节。
三、构造
既然是学习String
,那么第一件事就是了解我们应该怎么创建一个String
,一般有三个方法:
fn main() {
let s=String::from("hello 世界");
let mut s1=String::new();
s1.push_str("hello 世界");
//s1+="hello 世界"; //与上面的语句等价,即:追加字符串在后面
let s2="hello 世界".to_string();
println!("{}", s);
println!("{}", s1);
println!("{}", s2);
}
三个方法分别是调用from
函数、new
函数以及to_string
函数。
其中,from
与to_string
的功能是等价的,只是调用的对象不同而已,作用都是从一个字符串字面量直接构造出一个String
来。
而new
函数则是凭空产生一个String
,并且为空,如果想要让它存值就得将他声明为可变的(mut
),之后可以用push_str
函数或者+=
操作符来追加字符串。
最后输出的结果都是一样的:
hello 世界
hello 世界
hello 世界
除此之外,还有一个函数为with_capacity
:
let s=String::with_capacity(100);
它的作用与new
基本相同,唯一不同之处在于,这个函数需要一个参数来初始化其内部的内存大小,如果你事先知道自己需要多大的内存,那么建议你使用这个函数来构造一个String
而不是用new
。
至于原因,可以参考后文的:长度与容量
四、遍历
接下来,我们首先要看的就是如何对字符串进行遍历,用到的函数为as_bytes
与chars
。
首先是as_bytes
函数,看名字也知道,它的意思就是:作为字节。
所以它的功能就是遍历字符串的所有字节,就可以这样写: