为什么是斐波那契数列

斐波那契数列十分适合用来实战rust的迭代器,算法也很简单,一目了然。这个例子可以用来学习Iterator的使用,十分适合刚学习了rust的迭代器章节后用来练练手。

代码实战

don't bb, show me the code

  1. struct Fib(usize, usize);
  2. impl Fib {
  3. fn new() -> Fib {
  4. Fib(0, 1)
  5. }
  6. }
  7. impl Iterator for Fib {
  8. type Item = usize;
  9. fn next(&mut self) -> Option<usize> {
  10. *self = Fib(self.1, self.0 + self.1);
  11. Some(self.0)
  12. }
  13. }
  14. fn main() {
  15. let last = 20;
  16. println!("fib({}) result: {:?}", last, Fib::new().take(last).collect::<Vec<usize>>());
  17. }

分解知识点

  1. 代码定义了一个名字为Fib的元组结构体(tuple structs)。因为我们的实现封装了实现细节,没必要定义一个具名结构体。

    网上有给出其他定义了名称的结构体,个人觉得有点多余了。比如这样
  1. struct Fibonacci {
  2. a: u64,
  3. b: u64,
  4. }
  1. 第二点就是如何实现Iterator,关键就两点,定义关联类型和实现next方法
  1. impl Iterator for Fib {
  2. // 1. 定义关联类型为usize
  3. type Item = usize;
  4. // 2. 实现next方法,这里也是主要的逻辑
  5. fn next(&mut self) -> Option<usize> {
  6. *self = Fib(self.1, self.0 + self.1);
  7. Some(self.0)
  8. }
  9. }
  1. 第三点是*self = Fib(self.1, self.0 + self.1);; self被定义为了可变引用(&mut), 这里*self 解引用为Fib类型。

    另外一种写法
  1. self = &mut Fib(self.1, self.0 + self.1);

上面定义了一个可变引用 &mut Fib 赋值给self,rust编译器直接提示

  1. |
  2. 12 | self = &mut Fib(self.1, self.0 + self.1);
  3. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot assign to immutable argument
  4. error[E0716]: temporary value dropped while borrowed
  5. --> src\main.rs:12:21
  6. |
  7. 11 | fn next(&mut self) -> Option<usize> {
  8. | - let's call the lifetime of this reference `'1`
  9. 12 | self = &mut Fib(self.1, self.0 + self.1);
  10. | ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
  11. | | |
  12. | | creates a temporary which is freed while still in use
  13. | assignment requires that borrow lasts for `'1`

提示借用了临时变量,临时变量会被丢弃掉。其实就是&mut Fib 只是一个可变借用,在被借用给self后就会马上失效了,self就会指向一个悬垂指针, rust编译器肯定不会让这种情况发生的(强行解释一波,欢迎打脸)。

所以正确的做法是直接让self获取新创建的Fib的所有权就行了。也就是*self = Fib(self.1, self.0 + self.1);

  1. 第四点是Fib::new().take(last).collect::<Vec<usize>>()。 这里直接在println宏里打印结果,编译器推断不出需要collect的类型,需要使用collect::标注。

    除非是下面这种写法,编译器能自动推断出来

  1. let result: Vec<usize> = Fib::new().take(last).collect();
  2. println!("fib({}) result: {:?}", last, result);

总结

本文通过rust iterator来实现斐波那契数列,需要掌握一下要点

  • 元组结构体写法
  • 如何实现iterator trait
  • collect:: 帮助编译器推断类型


rust实战系列 - 使用Iterator 迭代器实现斐波那契数列(Fibonacci )的更多相关文章

  1. python实现斐波那契数列(Fibonacci sequence)

    使用Python实现斐波那契数列(Fibonacci sequence) 斐波那契数列形如 1,1,2,3,5,8,13,等等.也就是说,下一个值是序列中前两个值之和.写一个函数,给定N,返回第N个斐 ...

  2. 斐波那契数列(Fibonacci) iOS

    斐波那契数列Fibonacci 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2 ...

  3. 使用一位数组解决 1 1 2 3 5 8 13 数列问题 斐波纳契数列 Fibonacci

    斐波纳契数列 Fibonacci 输出这个数列的前20个数是什么? 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 使用数组实现输出数列的前30 ...

  4. 使用并行的方法计算斐波那契数列 (Fibonacci)

    更新:我的同事Terry告诉我有一种矩阵运算的方式计算斐波那契数列,更适于并行.他还提供了利用TBB的parallel_reduce模板计算斐波那契数列的代码(在TBB示例代码的基础上修改得来,比原始 ...

  5. Go斐波拉契数列(Fibonacci)(多种写法)

    1 前言 斐波拉契数列有递归写法和尾递归和迭代写法. 2 代码 //recursion func fib(n int) int{ if n < 2{ return n }else{ return ...

  6. poj3070_斐波那契数列(Fibonacci)

    用矩阵求斐波那契数列,快速幂log(n),只用求最后4位(加和乘的运算中前面的位数无用) #include <stdio.h> #include <stdlib.h> int ...

  7. 练习六:斐波那契数列(fibonacci)

    题目:斐波那契数列. 程序分析:斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.34.……. 在数学上,斐波那契数列 ...

  8. Java实现斐波那契数列Fibonacci

    import java.util.Scanner; public class Fibonacci { public static void main(String[] args) { // TODO ...

  9. k阶斐波那契数列fibonacci第n项求值

    已知K阶斐波那契数列定义为:f0 = 0,  f1 = 0, … , fk-2 = 0, fk-1 = 1;fn = fn-1 + fn-2 + … + fn-k , n = k , k + 1, … ...

随机推荐

  1. 【LeetCode】334. Increasing Triplet Subsequence 解题报告(Python)

    [LeetCode]334. Increasing Triplet Subsequence 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode. ...

  2. Unsupervised Domain Adaptation by Backpropagation

    目录 概 主要内容 代码 Ganin Y. and Lempitsky V. Unsupervised Domain Adaptation by Backpropagation. ICML 2015. ...

  3. 使用 Eclipse 可视化插件 windowbuilder 进行Java GUI开发(插件安装的两种方法)

    对于Java GUI开发 其实最方便的方法是用插件制作,当然先了解完代码原理是最好的. eclispe安装windowbuilder有两种方式,一种是离线安装,一种是在线安装. 一.第一种在线安装: ...

  4. Ranger-Hdfs插件安装

    Ranger-Hdfs插件ranger-0.6.0-hdfs-plugin安装到Hdfs的所有NameNode节点, 其他的DataNode节点不需要安装. 1. 登陆hdfs安装的用户,hdfs/z ...

  5. go语言 装饰器模式

    package decoratorimport ( "fmt" "reflect")func Decorator(decoPtr, fn interface{} ...

  6. [学习笔记] Oracle字符串函数、日期函数、数值函数、转换函数、聚合函数

    函数 单行函数:对一行数据进行操作的函数,如字符串函数.数值函数.转换函数.日期函数等. 聚合函数:同时对多行数据进行操作,如求和函数等. 字符串函数 函数 说明 ASCII(X) 求字符X的ASCI ...

  7. 如何修改文件的 “创建时间” 和 “修改时间”(Windows Linux macOS)

    请访问原文链接:https://sysin.org/blog/how-to-change-file-date,查看最新版.原创作品,转载请保留出处. 作者:gc(at)sysin.org,主页:www ...

  8. mybatis学习笔记(三)

    使用mapper接口来实现数据操作 创建UserMapper接口,添加方法,方法名要与UserMappper.xml中id所一致并且接口名要与编写sql语句的xmL文件名同名.namespace 中的 ...

  9. 使用用支付宝时,返回的数据中subject为中文时验签失败

    解决方法为: 来自为知笔记(Wiz)

  10. java 封装 总结

    1.前言 老是被问什么是java 封装...很基础的一个问题 ,其实我们一直在写的东西但不知道怎么称呼. 比如 在entity实体类 里面老用到的 getter 和 setter 方法其实就是封装的方 ...