String 类型的变量本质是一个存放在栈上的胖指针(当然调用过程中,不用显示地按指针那样处理),共有三个字段:
&String 则表示对 String 类型数据的一个引用,也可以理解成是对上面所说的胖纸针的一个引用,示意图如下:

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

引用的本质就是指针,使用上略有不同,但这里为了更好地描述,我就把这两者概念模糊地来讲了。
【栈】&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中找到对应字符串,然后拷贝至堆中,返回地址、长度、容量字段。

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();
}
常见的转化就不赘述了,可以参考这位博主的文章
《rust中String,&str,Vec 和&[u8]的惯用转换》https://zhuanlan.zhihu.com/p/372082802
&String和&str 其实都可以看成是对< u8 >序列数据的引用,只不过结合上面的分析可以看出:&String最终指向的数据只会存在于堆上,而&str指向的数据则不然。可以完美地用&str替换&String(表全长String的切片),反过来就不行。
这也是字符串引用类型通常都是使用&str的原因。

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`