rust &String 和 &str 区别

1 String / &String

String 类型的变量本质是一个存放在栈上的胖指针(当然调用过程中,不用显示地按指针那样处理),共有三个字段:

  • 1 pointer: 指向实际字符串值的地址,值是存放在堆上可变字节缓冲区;
  • 2 length: 值Vec< u8 >长度 / 元素个数;
  • 3 capacity: 当前缓冲区容量,当值的长度溢出时,寻找新的合适区间,将值重新拷贝分配到新的内存;同时更新三个字段。

&String 则表示对 String 类型数据的一个引用,也可以理解成是对上面所说的胖纸针的一个引用,示意图如下:

rust &String 和 &str 区别_第1张图片

2 str / &str

str表示不可变且长度未知的u8类型数据序列,这样的数据序列是可以存在于内存的多种地方的;由于其长度未知,强安全的RUST在编译时无法通过,所以str类型数据无法独立使用,通常都采取其引用的形式,也就是字符串切片&str,一个存放在栈上的胖指针(指针本身长度是确定的),其包含两个字段:

  • 1 pointer: 指向实际字符串值的地址;
  • 2 length: 数据[u8]长度 / 元素个数。
    示意图如下:
    rust &String 和 &str 区别_第2张图片

3 &String 和 &str的比较

3.1 引用/指针

引用的本质就是指针,使用上略有不同,但这里为了更好地描述,我就把这两者概念模糊地来讲了。

  • 【栈】&String ->【栈】String -> 【堆】value

  • 【栈】&str -> 【?】value (str)
    str可以在
    1)静态存储区(static storage):最常见的字面量 “foo” 类型便是 &'static str;字面量会以硬编码的方式写入程序的二进制文件中,当程序运行时,加载至ROM(Read Only Memory);
    2)堆上缓冲区数据

    // let s: &String = &String::from("rust"); // 隐式推断, 类型会作为&String处理
    let s: &str = &String::from("rust"); // 显示标注,这里&str可以理解成是对String的全长切片
    

    其中,from()里的字符串字面量"rust"也会以硬编码形式写入二进制文件中,程序运行时,加载至ROM;创建String变量时,会在ROM中找到对应字符串,然后拷贝至堆中,返回地址、长度、容量字段。
    rust &String 和 &str 区别_第3张图片

    3)栈上的数据:分配在栈上的< u8 >数组

    use std::str;
    fn main() {
    	let arr: [u8; 4] = [b'r', b'u', b's', b't']; // b 将char unicode转换为utf-8
        let stack_str: &str = str::from_utf8(&arr).unwrap(); 
    }
    

3.2 类型转换

常见的转化就不赘述了,可以参考这位博主的文章

《rust中String,&str,Vec 和&[u8]的惯用转换》https://zhuanlan.zhihu.com/p/372082802

&String&str 其实都可以看成是对< u8 >序列数据的引用,只不过结合上面的分析可以看出:&String最终指向的数据只会存在于堆上,而&str指向的数据则不然。可以完美地用&str替换&String(表全长String的切片),反过来就不行。
这也是字符串引用类型通常都是使用&str的原因。
rust &String 和 &str 区别_第4张图片

    let s1:&str = &String::from("rust");
    let s2:&String = &String::from("rust");
    let s1:&str = "rust";
    // let s2:&String = "rust"; //类型匹配错误, mismatched types expected reference `&String` found reference `&'static str`

你可能感兴趣的:(rust,rust,算法,开发语言)