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

我们知道,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 :3
love_china[0] :Some('忠')
=>"love" =>bytes: 4
'l', =>bytes:1
'o', =>bytes:1
'v', =>bytes:1
'e', =>bytes:1
normal[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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值