前言

上一篇,介绍了Rust语言的

  • 结构体的函数和方法实现
  • 枚举的函数和方法实现
  • 模块简介

这一篇,我们介绍一下Rust中的复杂数据类型

  • 集合体

    • 数组
    • 元组
    • 向量
    • 哈希
    • 切片
  • 迭代器

集合体(Collections)

在编程实践中,显然会遇到处理“组团”数据的情况,这自然需要复杂数据类型来呼应,那么集合体就出现了,Rust提供了多种这样的内建类型。

本节,首先看下数组和元组。然后,看下标准库中的动态集合类型,主要介绍向量vectors(列表list)和哈希图hashmaps(键/值,key/value)。最后,引出切片slices,以其进入复杂数据的内部一看究竟。

数组(Arrays)

先从Rust数组开始,与其他语言的数组类似,要求定长和同类型,用[T, N]表示,其中T为任意类型,N为数组中元素的个数,不能是一个变量,建议使用常量usize值

看下这个代码实例:

// arrays.rsfn main() { let numbers: [u8; 10] = [1, 2, 3, 4, 5, 7, 8, 9, 10, 11]; let floats = [0.1f64, 0.2, 0.3]; println!("Number: {}", numbers[5]);println!("Float: {}", floats[2]);
}

以上代码结果为

第4,5行分别给出了两种初始化数组的方式,第一种是标准方式,第二种是把类型放在一个元素的位置并加上前缀指定类型,显得很灵活。

元组(Tuples)

与数组不同的是,元组中可以存放不同类型的数据,因此是一种异质性的集合体,在为函数传参或者做返回值方面用处颇大。

// tuples.rsfn main() { let num_and_str: (u8, &str) = (40, "Have a good day!");println!("{:?}", num_and_str);let (num, string) = num_and_str;println!("From tuple: Number: {}, String: {}", num, string);
}

以上代码结果为

可见,第4-5行,定义并提取一个元组的值,第6-7行,对元组进行分解赋值。

向量(Vectors)

比起数组,向量的好处,是不必提前定义内容和长度,这是一种与时俱进的类型,显然是动态的,在栈上分配空间,可以通过调用Vec::new构造函数或使用Vec ![]宏进行创建。

好,上代码:

// vec.rsfn main() {let mut numbers_vec: Vec<u8> = Vec::new(); numbers_vec.push(1); numbers_vec.push(2); let mut vec_with_macro = vec![1]; vec_with_macro.push(2);let _ = vec_with_macro.pop();    // value ignored with `_`let message = if numbers_vec == vec_with_macro {"They are equal"} else {"Nah! They look different to me"};println!("{} {:?} {:?}", message, numbers_vec, vec_with_macro);
}

简单分析一下,这里分别用两种方式创建向量:

第4行的number_vec 和 第8行的vec_with_macro ;而后利用push()和pop()进行增删数据。

在这里还有诸多用法,读者可以自己再跑跑。

std::vec::Vec - Rust​doc.rust-lang.org

实际上向量也可以利用for 循环来体现其迭代器性质。

上述代码结果如下

哈希(Hashmaps)

Rust不会忘记提供映射格式来存储键值数据的,相关功能来自于标准库std::collections模块:

名为HashMap,通过HashMap::new函数来创建。

看下代码:

// hashmaps.rsuse std::collections::HashMap; fn main() { let mut fruits = HashMap::new(); fruits.insert("apple", 3);fruits.insert("mango", 6);fruits.insert("orange", 2);fruits.insert("avocado", 7);for (k, v) in &fruits {println!("I got {} {}", v, k);}fruits.remove("orange");let old_avocado = fruits["avocado"];fruits.insert("avocado", old_avocado + 5);println!("nI now have {} avocados", fruits["avocado"]);
}

我们读一下:

  • 第3行,载入需要的模块std::collections::HashMap
  • 第6行,创建新的哈希图变量,fruits
  • 第7-10行,为该变量赋键值,使用inser方法
  • 第11-13行,打印赋值结果,涉及for循环,这里面是循环变量是元组(k,v),分别对应keys()和values()两种方法,面向引用变量&fruits进行迭代
  • 第15行,删除一个键,一对键值同时删除
  • 第16行,创建一个简单变量old_avocado,取得avocado在fruits中的数值
  • 第17行,为fruits中的avocado插入新值
  • 第18行,打印修改后的fruits["avocado"]数值

上述代码结果如下

一般而言,用于对HashMap类型的键进行散列的算法基于Robin hood开放寻址方案,但可以根据用例和性能使用自定义散列器替换

切片(Slices)

切片是一种”瞥见“集合类型数据内容的通用方法,大多数用例在于获得对集合类型中特定范围项的只读访问。

切片基本上是一个指针引用,指向由其他变量现所拥有的集合类型中的一个连续区间。

在底层,切片是指向堆栈或堆中某处数据的胖指针(fat pointer),这意味着切片,除了包含指向该数据的指针,还拥有指向多少数据的信息。

切片用&[T]表示,其中T是类型,用法与数组很相似。

我们看下代码:

// slices.rsfn main() {let mut numbers: [u8; 4] = [1, 2, 3, 4];{let all: &[u8] = &numbers[..];println!("All of them: {:?}", all);}{let first_two: &mut [u8] = &mut numbers[0..2];first_two[0] = 100;first_two[1] = 99;}println!("Look! I can modify through slices: {:?}", numbers);
}

我们读一下代码:

  • 第4行,创建一个可变绑定类型的数组变量 numbers
  • 第6行,创建&[u8]类型的切片,并使用&numbers指向数组number
    • [..]意味着全部引用该数组的数据
    • 之所以使用&是由于切片不能把数组数据拿来,只能引用,根源在于切片是unsized types,而这又是一个后续要详细谈的内容,读者莫急
  • 第11行,创建切片引用该数组的前两个位置
  • 第12-16行,通过切片改变原来数组的值,打印结果,成功

上述代码结果如下

不知道读者是否看到,代码中的第5,8,10,14行中有两组大括号,用来与不可变绑定变量进行区隔,否则不会通过编译的,这一点依然要到后续篇章才能讲清楚。

迭代器(Iterators)

迭代器不是什么新概念,其出现是以一种高效的方式过一下集合体中的元素,很多语言中都有,比如Python的iter(some_list) 和C++的 vector.begin() 。

其优势体现在

  • 提供一种优雅高级的遍历集合体数据的方式,而不用手写for循环了
  • 迭代器不会直接读取全部数据,而是采取懒惰(lazy)的方式,体现在
  • 如果只需要一个数据,那么就只访问该条数据
  • 还可以与多个转换操作(multiple transformation operations)链接在一起,
  • 比如根据条件筛选元素,并且在需要时才对转换进行计算
  • 提供next()方法,为读取下一条做准备

在Rust中,迭代器可以是实现其特性的任何类型,然后可以在for循环中使用此类型遍历其项,并实现在大多数标准库集合类型上,如Vector、HashMap、BTreeMap等等,也可以实现在自定义的类型上。

处理Rust中的集合类型时,迭代器是常用器械。实际上,Rust的for循环就被退化并隐藏为一个常规的包含next方法的match表达式,调用遍历对象。

此外,可以通过调用iter()或into_iter()将大多数集合类型转换为迭代器。

后边篇章还要结合新的知识点来进一步介绍迭代器的内容,本篇先到这里,很庆幸吧,这一节没有代码。

结语

本篇讲过了集合体和迭代器,里面蕴含了一些尚未揭开的谜团,请读者耐心一下,后面都会一一说明。

下一篇会先讲一下Rust中的项目管理。

主要参考和建议读者进一步阅读的文献

The Rust Programming Language​doc.rust-lang.org

Rust编程之道,2019, 张汉东

The Complete Rust Programming Reference Guide,2019, Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger

Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger

Beginning Rust ,2018,Carlo Milanesi

Rust Cookbook,2017,Vigneshwer Dhinakaran

哪些集合不能使用迭代器_Rust能力养成之(6):集合体与迭代器相关推荐

  1. rust有准星_Rust能力养成系列之(2):功能抽象

    前言 上一篇,介绍了上一篇,介绍了Rust语言的安装与编译 基本数据类型 变量声明和不可变绑定 这其中已经蕴含着Rust精华的成分了.本篇内容将涉及常规函数 闭包 字符串 函数(Function) 一 ...

  2. rust门卡有什么用_Rust能力养成之(10)用Cargo进行项目管理:扩展 调用与优化

    前言 上一篇我们讲了Cargo运行测试 Cargo运行实例 Cargo工作空间 当然,Cargo也能够进行扩展,合并外部工具以增强开发体验,在设计上,其可扩展性已经达到非常丰富和恰当的程度.Cargo ...

  3. javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...

    javascript迭代器 by rajaraodv 通过rajaraodv JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, ...

  4. STL中迭代器的作用,有指针为何还要迭代器

    请你来说一下STL中迭代器的作用,有指针为何还要迭代器 参考回答: 1.迭代器 Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴 ...

  5. 迭代器 组合模式 java_设计模式(九)迭代器模式与组合模式

    迭代器与组合模式 面对不同的问题,自然会用到不同的数据结构,甚至相同的问题也可以用不同的数据结构来实现.比如数组和ArrayList都可以构造一个列表. 但当想获得集合内的元素时,直接的取用就会涉及到 ...

  6. 大话设计模式之爱你一万年:第二十章 行为模式:迭代器模式:让遍历标准化:1. 迭代器模式

    如果要问java中使用最多的一种模式,答案不是单例模式,也不是工厂模式,更不是策略模式,而是迭代器模式,先来看一段代码吧: /*** 测试Iterator** @author 悟纤「公众号Spring ...

  7. java迭代器的原理_小学生之Java中迭代器实现的原理

    一. 引言 迭代这个名词对于熟悉Java的人来说绝对不陌生.我们常常使用JDK提供的迭代接口进行java collection的遍历: Iterator it = list.iterator(); w ...

  8. Python zip() 函数--多个迭代器取元素组合成一个新的迭代器

    目录 Python3 元组 描述 语法 实例 1.当zip()函数中只有一个参数时 2.当zip()函数有两个参数时 3.zip()函数的应用 Python3 元组 Python 的元组与列表类似,不 ...

  9. C++日记——Day5:迭代器、begin()/end(),rbegin()/rend()、迭代器失效、const_iterator

    迭代器简介 迭代器是一种遍历容器内元素的一种数据类型,这种数据类型感觉有点像指针,我们理解的时候可以理解为欸带起用来指向容器中某个元素. string,vector,[],很少用[],更常用的访问方式 ...

最新文章

  1. Centos下用lamp搭建日志服务器
  2. 前端框架Bootstrap 教程
  3. 机电传动控制第三次作业
  4. Python递归实现汉诺塔
  5. mysql数据表中取几列_MySQL实现表中取出随机数据
  6. linux ls命令shell脚本位置,linux - shell脚本到ls并在ls上执行命令结果 - SO中文参考 - www.soinside.com...
  7. 计算机408考研专业课思维导图(计算机组原理、数据结构、操作系统、计算机网络)
  8. (个人)AR电子书系统创新实训第三周(1)
  9. 华为手机使用应用沙盒动态修改imsi参数
  10. linux底层技术,Linux后端程序成长关键技术之底层体系结构
  11. str_rot13() 函数
  12. C语言中getch()的用法
  13. 她的话指引了很多人的未来生活———亦舒
  14. linux查看文件大小ls
  15. 关于MacPorts
  16. 海天蚝油《挑战不可能》实测5G超强传输能力
  17. 局域网 --- 共享文件夹设置与访问
  18. oracle网页客户端工具
  19. Allegro172版本DFM规则之DFA outline
  20. Python脚本运行出现语法错误

热门文章

  1. 阿里二面:怎么解决MySQL死锁问题的?
  2. JEECG 智能开发平台二次开发帮助文档
  3. Linux文本查看命令之cat
  4. 【noi 2.6_2421】Exchange Rates(DP)
  5. 文件批量传输组件作为架包使用说明
  6. HBase使用场景和成功案例 (转)
  7. POI--HSSFCellStyle类
  8. Linux各个目录的作用及内容
  9. PHP 中 shell_exec() 中的反撇号操作符的变体 可用作后门
  10. 第四章、PL/SQL基础