String []字符串运算符,向量切片链接

String []字符串运算符,向量切片链接,string,vector,rust,String,Vector,Rust,为什么你要在绳子上走才能找到nᵗʰ执行s[n]时字符串的字母,其中s是字符串。(根据) 据我所知,字符串是一个字符数组,而字符是一个4字节数组或4字节数数组。所以得到第n个字母类似于这样做:v[4*n..4*n+4],其中v是向量 v[i..j]的成本是多少 我假设v[I..j]的成本是j-I,因此s[n]的成本应该是4。注意:Rust编程语言的第二版有一个改进的、平滑的解释,您可能也希望阅读。下面的答案虽然仍然准确,但引用了该书第一版 我将引用这本书(),试图澄清这些关于生锈的字符串的误解

为什么你要在绳子上走才能找到nᵗʰ执行s[n]时字符串的字母,其中s是字符串。(根据)

据我所知,字符串是一个字符数组,而字符是一个4字节数组或4字节数数组。所以得到第n个字母类似于这样做:v[4*n..4*n+4],其中v是向量

v[i..j]的成本是多少


我假设v[I..j]的成本是j-I,因此s[n]的成本应该是4。

注意:Rust编程语言的第二版有一个改进的、平滑的解释,您可能也希望阅读。下面的答案虽然仍然准确,但引用了该书第一版


我将引用这本书(),试图澄清这些关于生锈的字符串的误解

“字符串”是编码为UTF-8字节流的Unicode标量值序列。所有字符串都保证是UTF-8序列的有效编码

记住这一点,再加上UTF-8代码点的大小是可变的(1到4字节,取决于字符),所有生锈的字符串,无论是
&str
还是
字符串
,都不是字符数组,不能这样处理。进一步解释了在切片上的原因:

因为字符串是有效的UTF-8,所以它们不支持索引:

let s = "hello";

println!("The first letter of s is {}", s[0]); // ERROR!!!
通常,使用[]访问向量的速度非常快。但是,由于UTF-8编码字符串中的每个字符可以是多个字节,因此必须遍历该字符串才能找到nᵗʰ字符串中的字母。这是一个非常昂贵的操作,我们不想被误导

与问题中提到的不同,我们无法执行
s[n]
,因为尽管理论上这允许我们在恒定时间内获取第n个字节,但该字节本身并不能保证有任何意义

v[i..j]的成本是多少?

切片的成本实际上是恒定的,因为它是在字节级别完成的:

可以使用切片语法获取字符串的切片:

let dog = "hachiko";
let hachi = &dog[0..5];
但请注意,这些是字节偏移量,而不是字符偏移量。因此,这将在运行时失败:

let dog = "忠犬ハチ公";
let hachi = &dog[0..2];
出现此错误时:

忠犬ハチ公不要躺在床上
字符边界'

基本上,切片是可以接受的,并将生成该字符串的新视图,因此不制作副本。但是,仅当您完全确定偏移量在字符边界方面是正确的时,才应使用该选项

为了迭代字符串的每个字符,您可以调用
chars()

即使考虑到这一点,请注意,如果希望在UTF-8中处理字符修饰符(它们本身是标量值,但也不应单独处理),处理Unicode字符可能并不完全是您想要的。现引述:

fn字符(&self)->chars

返回字符串片段的字符的迭代器

由于字符串片由有效的UTF-8组成,我们可以按字符遍历字符串片。此方法返回这样的迭代器

重要的是要记住,char表示一个Unicode标量值,可能与您对“字符”的理解不符。在grapheme集群上的迭代可能是您真正想要的

记住,角色可能与你对角色的直觉不符:

let y = "y̆";

let mut chars = y.chars();

assert_eq!(Some('y'), chars.next()); // not 'y̆'
assert_eq!(Some('\u{0306}'), chars.next());
assert_eq!(None, chars.next());
板条箱提供了定义grapheme群集边界的方法:

extern crate unicode_segmentation;

use unicode_segmentation::UnicodeSegmentation;

let s = "a̐éö̲\r\n";
let g = UnicodeSegmentation::graphemes(s, true).collect::<Vec<&str>>();
let b: &[_] = &["a̐", "é", "ö̲", "\r\n"];
assert_eq!(g, b);
extern板条箱unicode\u分段;
使用unicode_分段::unicode分段;
设s=“a̐éỏ̲\r\n”;
设g=UnicodeSegmentation::graphemes(s,true);
设b:&[̐]=&[“a̐”,“é”,“ỏ̲”,“r\n”];
断言!(g,b);

如果您确实希望将字符串视为一个码点数组(严格来说与字符不同;有组合标记、表情符号和单独的肤色修饰符等),可以将其收集到
Vec

fn main(){

让我们=“10仅仅是Rust如何让人们成为更好的程序员的另一个例子。我只是不理解反对票。这是一个合理的问题,也是一个常见的误解。对这个问题稍加改进也无妨,也许可以将其从“Rust[]运算符如何处理字符串”改为锈字符串是如何切片的,它们的字符是如何索引的"。也有一些陈述与给定的链接相矛盾,并且很容易吸引反对票。@dpc.pw可能是因为这里已经有很多问题,如果OP可以更努力地搜索,或者在提问之前展示他们付出的努力,那么可以解释这一点。啊,好的,我明白了:字符串不能是数组因为每一个字母都可以是C++ char(1字节)或Unicode字符(4字节)。所以它是一个序列(链表?)。是一个数组。如果我想使用字符串作为数组,我可以使用UTF-8数组吗?UTF-8是一种将Unicode代码点可变长度编码为字节的编码。每个代码点可以结束为1、2、3或4个字节。碰巧ASCII字符(英语中常用)结束为1个字节(与ASCII值相同)。一个小问题:Unicode标量值不能是可变大小的,因为它们只是数字,在计算机中没有定义的表示形式。它是大小可变的UTF-8代码点,每个代码点编码一个Unicode标量值。例如,
char
,作为UTF-32代码点,其大小是固定的,但它仍然是encode一个Unicode标量值。奇怪的是,文档中说:“grapheme集群上的迭代可能是您真正想要的”,但Rust并没有提供这样做的方法。或者这实际上不是一件常见的事情吗?事实上,这是一种可能。我只是选择提及
chars()
,因为它是懒惰的,而且更多
extern crate unicode_segmentation;

use unicode_segmentation::UnicodeSegmentation;

let s = "a̐éö̲\r\n";
let g = UnicodeSegmentation::graphemes(s, true).collect::<Vec<&str>>();
let b: &[_] = &["a̐", "é", "ö̲", "\r\n"];
assert_eq!(g, b);