rust语言基础学习rust中的slice类型
今天来学习Rust中的slice类型。 为什么需要slice类型
为什么Rust会提供slice类型呢?
Rust中的借用(Borrow语义)可以将一个值在其所有权不发生转移的情况下,借给其他变量使用,借用通过创建引用来实现,Rust中创建引用的行为被称为借用。 但对于常用的集合类型例如 Vec , String (String的底层是Vec ),这些集合类型的引用类型&Vec , &String ,引用的将时整个集合的内容。
在一些特定的场景中,我们需要只引用集合中一段连续的元素序列,而不是引用整个集合的内容。 因此Rust提供了一类slice类型,使用slice类型可以只引用集合中一部分连续的元素。 。
我们知道引用类型是没有所有权的类型,slice作为"部分引用"也是没有所有权的类型,所以slice通常以"借用"的形式存在。
rust中slice的语法是使用 [start_index..end_index] 指定的范围创建一个slice,包含start_index处的元素,而不包含end_index处的元素,rust中切片slice划得的元素个数是end_index - start_index (在这点上与go语言中的slice十分相似)。
例如有一个集合变量 x ,则创建一个基于x的slice的语法是&x[start_index..end_index] ,注意创建的slice是以"借用"形式存在,所以在x前面加了引用操作符& 。字符串slice: str
str 是rust核心中内置的字符串slice,它通常以借用&str 的形式存在。
&str 是String 中一部分值的引用。
例1 : fn main() { let s = String::from("hello world"); let hello: &str = &s[..5]; // hello变量的类型可以自动推断, 这里显式给出 let mid = &s[4..7]; let world = &s[6..]; println!("{}", hello); // "hello" println!("{}", mid); // "o w" println!("{}", world); // "world" }
需要注意字符串slice指定范围边界的索引必须是有效的UTF-8字符串边界,如果从一个多字节字符的中间位置创建字符串slice,程序将会panic(在这点上与go语言对string类型进行切片操作是不同的,在go中不会panic)。
例2 : fn main() { let s = String::from("你好 世界"); let hello = &s[..1]; // thread "main" panicked at "byte index 1 is not a char boundary; it is inside "你" (bytes 0..3) of `你好 世界`" println!("{}", hello); }
Rust中字符串字面量实际上就是字符串slice &str。
例3 : let hello :&str = "hello";
上面代码中hello变量的类型是&str,它是一个指向二进制程序特定位置的字符串(程序加载到内的代码区一般在.rodata中的字符串),&str是一个不可变引用,字符串字面值是不可变的。
可以从一个slice创建另一个新的slice.
例4 : fn main() { let s = String::from("hello world"); let hello: &str = &s[..5]; let hel1: &str = &hello[..3]; let hel2: &str = &s[..3]; assert_eq!(hel1, hel2); } 更通用的slice类型
上面我们学习的字符串slice str 是专门针对字符串的slice类型。Rust中还提供了更加通用的slice类型。
通用的slice类型表示为 [T] ,一般以"借用"&[T] 的形式存在。
我们可以从一个数组创建slice,只引用数组的一部分;还可以从 Vec 创建slice,引用Vec集合的一部分元素。
例5 : fn main() { let arr: [i32; 3] = [1, 2, 3]; // arr是数组类型[i32; 3], 类型可自动推导, 这里显式给出 let vec: Vec = vec![2, 3, 4, 5]; // vec变量是Vec类型, 类型可自动推导, 这里显式给出 let s1: &[i32] = &arr[1..3]; // s1是类型为`&[i32]`的slice, 类型可自动推导, 这里显式给出 let s2: &[i32] = &vec[0..2]; // s2是类型为`&[i32]`的slice, 类型可自动推导, 这里显式给出 assert_eq!(s1, s2); println!("{:?}, {:?}", s1, s2); // [2, 3], [2, 3] } slice类型和Deref trait
之前我们学习过 Deref 和DerefMut 两个trait。Deref用于不可变引用的解引用操作,如 *v 。 实现Deref trait允许我们重载不可变引用的解引用运算符*。实现了Deref trait的智能指针可以被当做常规引用来对待。DerefMut用于可变引用的解引用操作,如 *v = 1; 。 实现DerefMut trait允许我们重载可变应用的解引用运算符*。实现了DerefMut trait的智能指针可以被当做常规可变引用来对待。
Rust中的 String 实现了Deref和DerefMut,String实现Deref中的关联类型Target是str 。因此,如果对String类型进行解引用操作的话,就得到了引用整个String的str 。
例6 : fn main() { let word = String::from("hello!"); let s: &str = &*word; println!("{}", s); // hello! // 打印word变量的地址 println!("{:p}", &word); // 0x7ffee56ebb98 // 打印word变量拥有值的堆内存地址 println!("{:p}", s); // 0x7f7f14c05d10 }
Rust中的 Vec 实现了Deref和DerefMut,Vec 实现Deref中的关联类型Target是[T] 。因此,如果对Vec 类型进行解引用操作的话,就得到了引用整个String的[T] 。
例7 : fn main() { let v = vec![1, 2, 3]; let s: &[i32] = &*v; println!("{:?}", s); // [1, 2, 3] // 打印v变量的地址 println!("{:p}", &v); // 0x7ffee9ce4b98 // 打印v变量拥有值的堆内存地址 println!("{:p}, {:p}", s, &v[0]); // 0x7f87b1d05c30, 0x7f87b1d05c30 }
有了本节对slice类型的学习,再来复习一下之前学过的"传参时Deref强制转换",实现Deref的类型的引用,会自动隐式强制转换为通过Deref所能转换的类型。
例8 : fn main() { let arr = [1, 2, 3]; let vec = vec![1, 2, 3]; foo(&vec); // Deref强制转换 foo(&arr); foo(&vec[..]); foo(&vec[..]); foo(&*vec); } fn foo(s: &[i32]) { println!("{:?}", s); }
例8中在设计foo函数签名时,设计参数为slice类型 &[i32] ,能够同时适用于&Vec 和&[i32] ,比将foo函数的参数设计成&Vec 更加灵活。参考https://kaisery.github.io/trpl-zh-cn/ch04-03-slices.html https://doc.rust-lang.org/std/slice/index.html https://doc.rust-lang.org/std/primitive.str.html https://doc.rust-lang.org/std/vec/struct.Vec.html https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-Deref
监控画面显示资源不足监控装上之后好好的,正常显示,突然有一天监控画面显示资源不足时,应急的办法就是把录像机电源开关重启一下!监控画面有个别的画面显示资源不足,遇到这种情况,是因为摄像机的分辨率超出录像
阿里巴巴女员工侵害案尘埃未落,都已不堪阿里巴巴女员工侵害案的热度已经消散,三个家庭的悲剧或许才刚刚开始。到底是女方为了个人的清白在自导自演,还是男士们酒壮怂人胆后的色心起意,目前还没有最终的定论,这起事件中有赢家吗?怕
某想倒计时风起于青萍之末!随着国内著名打假斗士司马南先生针针见血的六连问之后!联想无偿捐助美军的丑闻又被网友揭开坐实!随后司马先生又连续发文揭开了联想原本金融帝国的隐私!再加上柳传志自诩20
电商促销莫忘涉税,京东电商预收定金100万等预售业务如何交税?电商销售业务如火如荼,预付定金,跨店满300减50等促销活动琳琅满目,各种促销活动给电商财务带来挑战,特别是刚毕业的财务小白,如何纳税,何时纳税,一头雾水。下面举例进行总结,以供想
iPhone13一生之敌,正式发布全体起立!骁龙8Gen1移动平台高能亮相2021骁龙技术峰会作为高通有史以来最先进的旗舰级移动平台骁龙8Gen1集业界领先的5GAI游戏和影像等移动技术创新于一身将赋能下一代旗舰终
日本中小学教师不评职称,教育领先于世界,我们怎么理解?我虽然职称比较高了,但我认为评职称负作用还真不小,尤其是对于中小学教师。评职的副作用远远大于正面作用,很多人职称和能力并不成比例,还有很多人就是利用一些歪门邪道的手段搞到职称!如果
释放超融合实力华云数据助力电力建设工程公司重塑IT基础架构从VMware迁移到安超释放超融合实力华云数据助力电力建设工程公司重塑IT基础架构数字时代已然来临,科技企业面对的不仅是自身发展的问题,更多的是要向全产业赋能。尤其在国产化自主创新
高密自智的存储系统什么样?狒解芯机文字版2台通用服务器的体量,近2PB的存储容量不必发愁怎么管理,它还有与身材不相符的智能能自愈,更治愈E企研究院开启高能存储月,狒解芯机正式上线狒哥邀您观赏高密自智大数据存储平台鉴赏秀!
高通做东,小米OV荣耀中兴黑鲨齐聚一堂,场面竟然很和谐2021骁龙技术峰会,高通两天时间四连发,带来了全新一代骁龙8移动平台第3代骁龙8cx计算平台第3代骁龙7c计算平台以及第1代骁龙G3x游戏平台。其中大家关注度最高的自然便是全新一
路由器的盒子不要扔事情是这样的,大船搬家后,房子变大,房间变多了,之前的360V4路由器穿墙性能明显不足,主卧部分区域无法稳定使用5G频段信号。所以后来大船买了一款红米AC2100路由器,价格贵了几
年轻人的第一款LV,不一定非要包包,也可以是LV定制iPhone包治百病,尤其是LV的包包,对于很多女孩子来说,在年轻时,拥有一款LV包包就是当下的梦想。不过,年轻人刚出来工作,受限于消费水平,LV包包稍上档次的价格不菲。入手需割肉,且包虽治百