字符串及Rust中的字符串

字符串本身是远比我们想的那样更复杂的数据结构, 尤其是对于那些最开始接触的是更高级的编程语言的程序员来说尤其如此.

字符串的本质是一个字节的集合外加一些操作方法, 当它被解释为文本时这些方法提供了一些实用的功能.

在编程语言中, 对字符串的处理大致分为三类:

  • 第一种以C/C++为代表的是基本不做处理,编码、内存分配、性能优化、非法字符检查以及安全等问题全部交由程序员处理, 这样程序猿可以获得最大的自由度和控制力。
  • 第二种是java / C#/python/javascript等带有垃圾回收的高级语言的做法,编码、内存分配、性能优化等全部封装在runtime中, 这样操作简单对程序员十分友好, 但丧失了对字符串的控制力,在一些需要精确控制的地方无从下手, 并且存在一定的性能问题。
  • 第三种是rust这类部分封装,语言自身提供一堆工具,由程序员自行选择,但在语法上会产生很多噪音,对不理解背后原理的同学来说会感觉非常别扭,但这样可以做到性能与控制力的兼顾,也能给程序员一些知道和约束。

从计算机的角度来看,有三种方式理解字符串:字节标量值字形族(更接近人类语言中的字/字母的概念)

比如用用梵文书写的印度语单词 नमस्ते 它在内存中存储的u8看起来是有18个字节:

Rust展开
12
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135]

如果从Unicode标量值的角度看,也就是像Rust的char类型那样有6个字符,不过第4个和第6个不是字母,它们是发音符号并没有实际意义:

Rust展开
1
['न', 'म', 'स', '्', 'त', 'े']

最后从字形族的角度看,就是人所理解的构成单词的4个字母:

Rust展开
1
["न", "म", "स्", "ते"]

Rust 提供了多种不同的方式来解释计算机中存储的原始字符串数据,这样程序可以选择以何种方式表现它们,而与具体的人类语言无关。

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

String类型 是有标准库提供的,它并不存在于语言的核心部分。 String是可增长的, 可变的,有所有权的UTF-8的字符串类型。

Rust中还提供了一系列其他类型的字符串,比如:OsString、OsStr、CString和CStr。还有一些三方crate 提供一些其他的字符串类型选择。这些字符串类型能够提供以不同编码,或内存表现形式的文本存储。

String 类型的字符串大小是可以增加的,其内容也可以改变,就像可以放入更多数据来更新Vec一样。另外,String可以使用 + 或者format!来拼接字符串。

String 是有所有权的,因此需要注意数据的可用性

Try in playground

Rust展开
12345678
fn main(){

    let s1 = String::from("hello ");
    let s2 = String::from("world!");

    let s3 = s1 + &s2;   // s1 被移动了, 不能再继续使用了
    println!("{}", s3); 
}

- roadup -