rust圣经第八章中的string

之前看过对rust string的吐槽有点多,今天看了一下果然比较复杂,说说一个初学者的看法。

一般rust里面的字符串实际上有两种类型,第一种就是我们常见的不固定string,也就是我们使用String::from()这样的方式构建的一个类型,第二种类型是&str,实际上我们string类型的一个切片。

官网上给出了下面这样的例子:

    let s = String::from("hello world");

    let hello = &s[0..5];
    let world = &s[6..11];

如果在编辑器里面去看这个hello和world类型可以明确的看到,这两个都是&str的类型

我们可以注意到这个&str实际上带“&”指针符号的,而str又是string,这让我想起了前面学习过的reference的概念,string类型在作为参数进入函数之后,其所有权应该是被消耗掉的,&str类型作为一种reference,应该是会保留所有权的,因此我搞了个试验,如下

comsume_str(hello);
comsume_str(hello);


fn comsume_str(s: &str) {
    println!("{}", s)
}

这个comsume_str确实是能执行两次的,确实证实了上面的猜想。当然我在这个过程中遇到了一个小问题,我这边记录一下

fn main(){
    let s11 = String::from("hello world");

    let hello = &s11[0..5];
    let world = &s11[6..11];
    comsume_string(s11); //在这里产生了一个报错
    comsume_str(hello);
    comsume_str(hello);

}

fn comsume_string(s: String) {
    println!("{}", s)
}
fn comsume_str(s: &str) {
    println!("{}", s)
}

我想了一下原因,如果我在错误发生的这一行消耗掉s11的所有权,下面关于hello的reference也就没有了意义,于是我改了一下循序

fn main(){
    let s11 = String::from("hello world");

    let hello = &s11[0..5];
    let world = &s11[6..11];

    comsume_str(hello);
    comsume_str(hello);
    comsume_string(s11); //放到了这个位置

}

fn comsume_string(s: String) {
    println!("{}", s)
}
fn comsume_str(s: &str) {
    println!("{}", s)
}

换了位置之后果然不报错了,rust果然很严谨啊。

话题越说越远了,接下来还是要看看再第八章之中对string类型的拓展

第一部分是string类型初始化

这里新给了一个new函数去初始化一个字符串

//new初始化一个空字符串
 let mut s = String::new();
//to_string方法
s = "hello world".to_string(); 

教程上显示拥有display特征的都可以调用to_string,这里的tostring把一个$str变成了string并放入到我们可变的s空字符串中

第二部分是字符串的添加,或者说是拼接

首先是push_str的方式,这个方法的参数应该是一个&str,当然注意我们self,也就是这个s必须是可变的

   s.push_str("string");

 然后是push的方式,这个添加是char类型,依然要求我们的self是可变的

    s.push('l');

使用+的方式进行拼接,这个就有点复杂了,这里的+并不是简单的+,而是一个这样的方法fn add(self, s: &str) -> String

 let s3 = String::from("huangfeng");
 let s4 = s2 + &s3;
 println!("s4的值是:{}", s4); // 真是有点巧妙啊

也就是意味着+运算的顺序是不能变的,始终是string+&str

最后给了一个format的方式让你并且较长的字符串

 let s5 = format!("{} vs {}", s4, "hoih");
    println!("s5的值是:{}", s5);

这里我们看到了format后面有一个!符号,也就是和println!是一样的,暂时我的理解是,这并非是函数,因为其不消耗所有权(应该是吧,错误的话请指正),教程上有个专业名词来着,但是我忘了。

接下来教程讨论是字符串的难以切割的问题

实际上指的是难以通过&string[0]这样索引号方式获取的问题,因为每个字符所占的字节不一样多,但是还是可以通过这样的方式获取

let s6 = String::from("黄烽无敌");
    // let c1 = &s6[3];因为字符所占的字节不一样,所以这边不是好切割
    // 但是可以通过这样的方式拿取
    let first = &s6[0..3];
    println!("我的姓是{}", first);
    let s7 = String::from("he");
    // 现在我想拿到第一个字符
    let first_char = &s7[0..1];
    println!("第一个字母是{}", first_char);

也就是可以通过制定range方式来获取(比如中文占3个字节,我就拿取0-2),官网说这个first_char获取会报错,但是我这边是能拿到的。

最后一部分是两个遍历,分别是字节的遍历和字符rune的遍历

    for i in s6.as_bytes() {
        println!("{}", i);
    }

    for i in s7.chars() {
        println!("{}", i);
    }

没啥好说的,按照教程一步步来吧。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值