Rust : 危险! 关于字符串切片以及取值......

来源:互联网 发布:淘宝买小饰品文艺店铺 编辑:程序博客网 时间:2024/05/21 09:35

我们知道,Rust中字符串的切片容易会引起panic,千万要注意。主要是,Rust的切片,切的其中字节,这个说法有些抽象,如何能理解呢?

首先,对一个字符串,你认为其字符数和长度是一个什么样的概念?相等,不相等?

比如,对于ascii码字符串,

let same_string ="abc";println!("chars:{}, length:{}",same_string.chars().count(),same_string.len());// chars :3,length:3

当然,不都是这样的。

let other_string ="忠犬ハチ公";println!("chars:{}, length:{}",other_string.chars().count(),other_string.len());// chars :5,length:15

所以,最重要的是,Rust的切片,切的是字节,而不是字符。

一、Rust的切片操作

    //String    let t1 = "love".to_string();    println!("String =>t1:{:?}", &t1[2..]);//必须带&, =>ve    // &str    let t2 = "love";    println!("&str   =>t2:{:?}", &t2[2..]);//必须带& =>ve

好象看起来,很正常呀,没什么问题的。
如果碰到的全是a…z之类构成的,是可能没问题的,但其它的呢?

二、有没有意外?

既然是危险的操作,危险就是必然的。

// 一个“不正常”的例子    let love_china = "忠犬ハチ公";    println!("{:?}=>bytes :{:?}", love_china, love_china.bytes().len());    //println!("{:?}", love_china.len_utf8());    for i in love_china.chars() {        println!("{:?} =>bytes :{:?}", i, i.len_utf8());    }    println!("love_china[0] :{:?}", love_china.chars().nth(0));// 一个正常的例子    let normal = "love";    println!("=>{:?} =>bytes: {:?}", normal, normal.bytes().len());    for i in normal.chars() {        println!("{:?}, =>bytes:{:?}", i, i.len_utf8());    }    println!("normal[0] :{:?}", normal.chars().nth(0).unwrap());

output:

"忠犬ハチ公"=>bytes :15'忠' =>bytes :3'犬' =>bytes :3'ハ' =>bytes :3'チ' =>bytes :3'公' =>bytes :3love_china[0] :Some('忠')=>"love" =>bytes: 4'l', =>bytes:1'o', =>bytes:1'v', =>bytes:1'e', =>bytes:1normal[0] :'l'

发现什么没有?

    println!("love_china len:{:?}", love_china.len());// => len =15,而不是5!

知道问题所在了吧…….

(1) ‘忠’ =>bytes :3.

也就是说,’忠’字符却占3个字节,如果你去切1个字节,还会报什么呢,Rust只能panic了。

    let dd1 = &love_china[0..3];//切前3个字节=>'忠'.    println!("dd:{:?}", dd);

如果&love_china[0..2]=>切前2个字节,则会panic!.

(2) ‘l’, =>bytes:1。

象“love”其它的每个字符,都只占了1个字节,形成了字符位和字节位的刚好重合,给人一种“安全”的错觉。

三、正确的打开方式

1、单个字符的取值

下面是推荐的取字符串中正确的打开方式:.chars().nth(0)。

    println!("love_china[0] :{:?}", love_china.chars().nth(0));

那如果要取其中的两个字符呢? 思考一下…….

2、多个字符的取值

    let tt = "我爱工作,rust,julia!";    let t = tt.chars().into_iter().map(|x| x.to_string()).collect::<Vec<_>>();    println!("t:{:?}", t);    let ww: String = t[1..3].concat();    let qq: String = t[1..3].join("");    println!("ww:{:?} qq:{:?}", ww, qq);