如何理解Rust中的字符串(二)

简介: 如何理解Rust中的字符串(二)
在上一篇文章中介绍了Rust字符串中的&str(切片),这篇文章将介绍String类型。Rust中的String类型比其他语言的String更加复杂。

Rust中的String类型

通常说的字符串是哪一个?

Rust中所说的字符串为&str和String,而不是其中的一种

其他类型的字符串

Rust的标准库还包含了很多其他的字符串类型,如:OsString、OsStr、CString、Cstr

上面的类型有String结尾的,有Str结尾的,这两者的区别在于String结尾的为可获得所有权的类型,而Str结尾的为可借用的。

此外,某些Libaray create(第三方库)针对存储字符串可提供更多的选项

创建一个新的字符串(String)

  • 很多Vec\<T>的操作都可作用于String
  • String::new()函数
let mut s = String::new();

通常情况下,我们声明一个字符串都是带有初始值的。我们可以使用to_string()方法,可用于实现了Display trait的类型,包括字符串字面值

let data = "this is a data";
let s = data.to_string();
let s1 = "ssss ss".to_string();

此外,我们还可以使用String::from()函数来创建带初始值的字符串:

let s = String::from("ssss yige sss");

更新String

  • push_str()方法:把一个字符串切片附加到String:
let mut s = String::from("foo");
s.push_str("string is pushed");
println!("{}", s); //foostring is pushed

let mut s1 = "first ".to_string();
let s2 = String::from("ss");
s1.push_str(&s2);
println!("{}", s2); //ss

我们查看push_str的签名:pub fn push_str(&mut self, string: &str)传入的是一个引用,所以我们将s2传入s1后任然可以使用。

  • push()方法:把单个字符附加到String:
let mut x = "sss".to_string();
x.push('c');
println!("{}", x); //sssc
  • 使用+拼接字符串(前面为String类型,后面为一个&str)
let s1 = String::from("aa");
let s2 = String::from("bb");
let s3 = s1 + &s2;
println!("{}", s3); //aabb
//println!("{}", s1); //报错
println!("{}", s2); //bb

其中,s2为String类型,而&s2类型为&str,这是因为Rust会使用解引用进行类型的强制转换(deref coercion)

+类似于这个函数签名:add(self,s:&str)->String

如果我们连接多个字符串,使用+要这样写

let s1 = String::from("aa");
let s2 = String::from("bb");
let s3 = String::from("cc");
let s4 = s1 + "-" + &s2 + "-" + &s3;
println!("{}", s4); //aa-bb-cc

但我们有更灵活快速的方法:

  • format!宏:连接多个字符串:
let s1 = String::from("aa");
let s2 = String::from("bb");
let s3 = String::from("cc");
let s4 = format!("{}-{}-{}", s1, s2, s3);
println!("{}", s4); //aa-bb-cc
println!("{}", s1); //aa
println!("{}", s2); //bb
println!("{}", s3); //cc

我们可以发现format!println!有些相似,不过前者是返回一个String类型的值,而后者为打印值。并且,重要的是,format!不会获取任何变量的所有权。

对String按照索引的形式进行访问

按索引语法访问String的某部分,会报错:

let s1 = String::from("aa");
s1[1]; //the type String cannot be indexed by {integer}

所以,rust不支持索引语法访问String

内部表示

string是对Vec\<u8>的包装

  • len()方法
let s1 = String::from("aabbcc");
let len = s1.len();
println!("{}", len); //6

但并不是说len()方法的返回值为字符串的长度:

let s1 = String::from("Этострока"); //9个字符(俄文)
let len = s1.len();
println!("{}", len); //18

let s2 = String::from("哈哈哈哈"); //4个字符
let len1 = s2.len();
println!("{}", len1); //12

在俄语中Unicode标量值占两字节,中文占3个。

所以说如果使用索引,不一定能取到一个合法的字符,比如Э,它的Unicode标量值为:208,151。如果能够使用索引访问字符串,s1[0]将会取到208,这并不是一个合法的字符(就算合法,也不是用户所想要的),所以Rust直接不允许这种操作。

字节、标量值、字形簇(Bytes,Scalar Values,Grapheme Clusters)

Rust有三种看待字符串的方式:

  • 字节
  • 标量值
  • 字形簇(最接近所谓的“字母”)

我们现在来使用对应的方法来对String进行遍历

字节:

let s1 = String::from("Это");
for b in s1.bytes() {
    println!("{}", b);
}
//208
// 173
// 209
// 130
// 208
// 190

Unicode标量值:

let s1 = String::from("Это");
for c in s1.chars() {
    println!("{}", c);
}
// Э
// т
// о

字形簇(最接近所谓的“字母”),实现比较复杂,标准库中没有提供这个功能,可以安装第三方库。

Rust不允许对String类型进行索引的最后一个原因:

  • 索引操作应消耗一个常量时间(O(1))
  • 而String无法保证:需要遍历所有内容,来确定有多少个合法的字符

切割String

可以使用[]和一个范围来创建字符串的切片:

let s1 = String::from("Этострока");
let s = &s1[4..8];//参数为字节的位置
println!("{}", s); //ос
  • 必须谨慎使用
  • 如果切割时跨越了字符边界,程序就会panic:

(b1,b2),(b3, b4),(b5,b6),(b7,b8)如果从b3,b4之间切割,程序将会panic

Rust中的String并不简单

Rust选择将正确处理String数据作为所有Rust程序的默认行为,程序员必须在处理UTF-8数据之前投入更多的精力

不过这样的好处也是明显的:可防止在开发后期处理涉及非ASCII字符的错误。

相关文章
|
6月前
|
存储 Rust 程序员
Rust中数据类型详解:从整数到字符串
本文将详细解析Rust编程语言中的基本数据类型,包括整数、浮点数、布尔值、字符与字符串。我们将深入探讨每种数据类型的特性、使用场景以及它们在Rust中的实现方式,帮助读者更好地理解和应用这些基础元素。
|
6月前
|
设计模式 Rust JavaScript
【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数
【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数
84 0
|
2月前
|
存储 Rust 安全
30天拿下Rust之字符串
在Rust中,字符串是一种非常重要的数据类型,用于处理文本数据。Rust的字符串是以UTF-8编码的字节序列,主要有两种类型:&str和String。其中,&str是一个对字符数据的不可变引用,更像是对现有字符串数据的“视图”,而String则是一个独立、可变更的字符串实体。
43 0
|
6月前
|
算法 Java Go
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
50 0
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
|
6月前
|
C++ Python Rust
Rust每日一练(Leetday0015) 字符串相乘、通配符匹配、跳跃游戏II
Rust每日一练(Leetday0015) 字符串相乘、通配符匹配、跳跃游戏II
50 0
Rust每日一练(Leetday0015) 字符串相乘、通配符匹配、跳跃游戏II
|
6月前
|
Rust JavaScript 安全
Rust 笔记:Rust 语言中的字符串
Rust 笔记:Rust 语言中的字符串
181 0
|
Rust JavaScript 安全
Rust 笔记Rust 语言中的字符串
本文介绍 Rust 语言中的字符和字符串的用法。
199 0
Rust 笔记Rust 语言中的字符串
|
Rust 程序员 索引
Rust 标准库字符串类型String及其46种常用方法
String是一个可变引用,而&str是对该字符串的不可变引用,即可以更改String的数据,但是不能操作&str的数据。String 类型来自标准库,它是可修改、可变长度、可拥有所有权的同样使用UTF-8编码,且它不以空(null)值终止,实际上就是对Vec的包装,在堆内存上分配一个字符串。由&[u8]表示,UTF-8编码的字符串的引用,字符串字面值,也称作字符串切片。
427 1
|
存储 Rust API
如何理解Rust中的字符串(一)
如何理解Rust中的字符串(一)
|
3天前
|
Rust 安全 区块链
探索Rust语言:系统编程的新选择
【10月更文挑战第27天】Rust语言以其安全性、性能和并发性在系统编程领域受到广泛关注。本文介绍了Rust的核心特性,如内存安全、高性能和强大的并发模型,以及开发技巧和实用工具,展示了Rust如何改变系统编程的面貌,并展望了其在WebAssembly、区块链和嵌入式系统等领域的未来应用。