当前位置: 首页 > news >正文

企业手机建站系统建站公司哪个好

企业手机建站系统,建站公司哪个好,企业网站模块建设流程,淘宝客服推销做网站的技巧系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
【跟小嘉学 Rust 编程】十一、编写自动化测试
【跟小嘉学 Rust 编程】十二、构建一个命令行程序
【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包

文章目录

  • 系列文章目录
    • @[TOC](文章目录)
  • 前言
  • 一、闭包(Closures)
    • 1.1、闭包(Closures)
    • 1.2、Rust的闭包语法
      • 1.2.1、闭包语法形式
      • 1.2.1、闭包简化形式
    • 1.3、闭包的类型推导
    • 1.4、结构体中的闭包
    • 1.5、捕获环境中的值
      • 1.5.1、捕获环境的值
      • 1.5.2、闭包对内存的影响
      • 1.5.2、三种 Fn trait
        • 1.5.2.1、FnOnce
        • 1.5.2.2、FnMut
        • 1.5.2.3、Fn Trait
      • 1.5.3、move 和 Fn
      • 1.5.4、三种 Fn 的关系
    • 1.6、闭包作为函数返回值
  • 二、迭代器(Iterators)
    • 2.1、迭代器(Iterators)
    • 2.2、Iterator trait
      • 2.2.1、Iterator trait
      • 2.2.2、next 方法
    • 2.3、迭代方法
    • 2.4、消耗迭代器的方法
      • 2.4.1、sum 方法
      • 2.4.2、collect方法
    • 2.5、迭代器适配器
      • 2.5.1、map
      • 2.5.2、zip
      • 2.5.3、filter
      • 2.5.4、enumerate
    • 2.6、自定义迭代器
  • 四、性能对比:循环 VS 迭代器
  • 总结

前言

Rust的设计灵感来源于很多现存的语言和技术,其中一个显著的影响就是函数式编程(functional prigramming)。函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将韩式赋值给变量以供之后执行等等。

主要教材参考 《The Rust Programming Language》


一、闭包(Closures)

1.1、闭包(Closures)

Rust的闭包(Closures)是可以保存进变量或作为参数传递给其他函数的匿名函数。可以在一个地方创建闭包,然后在不同的上下文执行闭包运算。不同函数,闭包允许捕获调用作用域中的值。
例如:

  • 使用函数作为参数进行传递
  • 使用函数作为函数返回值
  • 将函数赋值给变量

1.2、Rust的闭包语法

1.2.1、闭包语法形式

Rust闭包在形式上借鉴了 Smalltalk 和 Ruby 语言,与函数最大的不同就是它的参数是通过 |param| 的形式进行声明的。

示例:闭包语法形式

|param1,param2,....|{语句1;语句2...返回表达式
}

1.2.1、闭包简化形式

如果只有一个返回表达式可以简化成如下形式

|param|返回表达式

1.3、闭包的类型推导

Rust 是静态语言,因此所有的变量都具有类型,但是得益于编译器的强大类型推导能力,在很多时候我们并不需要显式声明类型,但是函数和必须为所有参数和返回值指定类型。

为了增加代码可读性,有时候我们会显式地给类型进行标注,出于同样的目的,也可以给闭包标注类型。

let sum = |x:i32, y:32| -> 32{x + y
}

类型推导虽然很好用,但是它不是泛型,当编译器推导出一种类型后,它就会一直使用该类型。

1.4、结构体中的闭包

struct Cacher<T> where T: Fn(u32) -> u32 {query: T,value: Optional<u32>
}

此时 query 就是一个闭包,他的类型是 Fn(u32) -> u32 是一个特征,用来表示T 是一个闭包类型。

1.5、捕获环境中的值

1.5.1、捕获环境的值

闭包可以捕获环境中的值

fn main() {let x = 4;let equal_to_x = |z| z == x;let y = 4;assert!(equal_to_x(y));
}

如果你使用函数来实现,编译器会告诉我们无法捕获动态环境中的值。

1.5.2、闭包对内存的影响

当闭包从环境中捕获一个值时,会分配内存去存储这些值。对于有些场景来说,这种额外的内存分配会成为一种负担。与之相比,函数就不会去捕获这些环境值,因此定义和使用函数不会拥有这种内存负担。

1.5.2、三种 Fn trait

闭包捕获环境变量有三种途径,恰好对应函数参数的三种传入方式:转移所有权、可变借用、不可变借用,因此Fn Trait 也有三种。

1.5.2.1、FnOnce

该类型的闭包会拿走被捕获变量的所有权。该闭包只能运行一次。

fn fn_once<F>(func: F)
whereF: FnOnce(usize) -> bool,
{println!("{}", func(3));println!("{}", func(4));
}fn main() {let x = vec![1, 2, 3];fn_once(|z|{z == x.len()})
}

此时编译器就会报错,因为不能对已失去所有权的闭包变量进行二次调用。 错误提示告诉我们因为F没有实现Copy Trait ,所以会报错,那么我们添加约束,试试实现了Copy的闭包。

fn fn_once<F>(func: F)
whereF: FnOnce(usize) -> bool + Copy,// 改动在这里
{println!("{}", func(3));println!("{}", func(4));
}fn main() {let x = vec![1, 2, 3];fn_once(|z|{z == x.len()})
}

如果你想强制闭包取得捕获变量的所有权,那么可以在参数列表前面添加 move 关键字,这种用法通常用在闭包的生命周期大于捕获变量的生命周期时,例如将闭包返回或移入其他线程。

use std::thread;
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();

1.5.2.2、FnMut

它是可变借用的方式捕获了环境中的值,因此可以修改该值。

fn main() {let mut s = String::new();let mut update_string =  |str| s.push_str(str);update_string("hello");println!("{:?}",s);
}

复杂形式

fn main() {let mut s = String::new();let update_string =  |str| s.push_str(str);exec(update_string);println!("{:?}",s);
}fn exec<'a, F: FnMut(&'a str)>(mut f: F)  {f("hello")
}

1.5.2.3、Fn Trait

它是以不可变借用的方式捕获环境中的值,让我们把上面的代码中的 F 类型修改为Fn。

fn main() {let mut s = String::new();let update_string =  |str| s.push_str(str);exec(update_string);println!("{:?}",s);
}fn exec<'a, F: Fn(&'a str)>(mut f: F)  {f("hello")
}

从报错中很清晰的看出,我们的闭包实现的是 FnMut 特征,需要的是可变借用,但是在 exec 中却给它标注了 Fn 特征,因此产生了不匹配,再来看看正确的不可变借用方式:

fn main() {let s = "hello, ".to_string();let update_string =  |str| println!("{},{}",s,str);exec(update_string);println!("{:?}",s);
}fn exec<'a, F: Fn(String) -> ()>(f: F)  {f("world".to_string())
}

1.5.3、move 和 Fn

在上面我们讲解到 move 关键字对于 FnOnce的重要性,实际上使用了 move 的闭包依然可能实现了 Fn 和
Fn Mut 特征。

因为一个闭包实现了哪种 Fn 特征取决于该闭包如何使用被捕获的变量,而不是取决于闭包如何捕获它们。move 本身强调的就是后者,闭包如何捕获变量:

1.5.4、三种 Fn 的关系

实际上,一个闭包不仅仅实现一种 Fn trait,规则如下

  • 所有的闭包都自动实现了 FnOnce 特征,因此任何一个闭包都至少可以被调用一次
  • 没有移出所有捕获变量的所有权的闭包自动实现了 FnMut Trait
  • 不需要对捕获变量进行改变的闭包自动失效了 Fn Trait
pub trait Fn<Args> : FnMut<Args> {extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}pub trait FnMut<Args> : FnOnce<Args> {extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}pub trait FnOnce<Args> {type Output;extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

1.6、闭包作为函数返回值

fn factory(x:i32) -> Box<dyn Fn(i32) -> i32> {let num = 5;if x > 1{Box::new(move |x| x + num)} else {Box::new(move |x| x - num)}
}

二、迭代器(Iterators)

2.1、迭代器(Iterators)

迭代器模式:对一系列项执行某些人物,迭代器负责遍历每一项,确定序列何时完成。Rust的迭代器是惰性的,除非调用消费迭代器的方法,否则迭代器本身没有任何效果。

迭代器允许我们迭代一个连续的集合,例如数组、向量、hashMap等。

let v1 = vec![1, 2, 3];let v1_iter = v1.iter();for val in v1_iter {println!("{}", val);
}

2.2、Iterator trait

2.2.1、Iterator trait

所有的迭代器都实现了 Iterator trait,该 Trait 定义于标准库。定义大致如下。

pub trait Iterator {type Item;fn next(&mut self) -> Option<Self::Item>;// 省略其余有默认实现的方法
}

2.2.2、next 方法

每次返回迭代器中的一项,返回结果包裹在Some 里面,迭代结束返回None。

fn main() {let arr = [1, 2, 3];let mut arr_iter = arr.into_iter();assert_eq!(arr_iter.next(), Some(1));assert_eq!(arr_iter.next(), Some(2));assert_eq!(arr_iter.next(), Some(3));assert_eq!(arr_iter.next(), None);
}

2.3、迭代方法

iter:在不可变引用上创建迭代器
into_iter: 创建的迭代器会获得所有权
iter_mut: 迭代可变的引用

2.4、消耗迭代器的方法

2.4.1、sum 方法

调用 next 方法的方法叫做 消耗型适配器。 例如 :Sum 方法:取得迭代器的所有权。

fn main() {let v1 = vec![1, 2, 3];let v1_iter = v1.iter();let total: i32 = v1_iter.sum();assert_eq!(total, 6);// v1_iter 是借用了 v1,因此 v1 可以照常使用println!("{:?}",v1);// 以下代码会报错,因为 `sum` 拿到了迭代器 `v1_iter` 的所有权// println!("{:?}",v1_iter);
}

2.4.2、collect方法

use std::collections::HashMap;
fn main() {let names = ["sunface", "sunfei"];let ages = [18, 18];let folks: HashMap<_, _> = names.into_iter().zip(ages.into_iter()).collect();println!("{:?}",folks);
}

zip 是一个迭代器适配器,它的作用就是将两个迭代器的内容压缩到一起,形成 Iterator<Item=(ValueFromA, ValueFromB)> 这样的新的迭代器,在此处就是形如 [(name1, age1), (name2, age2)] 的迭代器。

然后再通过 collect 将新迭代器中(K, V) 形式的值收集成 HashMap<K, V>,同样的,这里必须显式声明类型,然后 HashMap 内部的 KV 类型可以交给编译器去推导,最终编译器会推导出 HashMap<&str, i32>,完全正确!

2.5、迭代器适配器

2.5.1、map

既然消费者适配器是消费掉迭代器,然后返回一个值。那么迭代器适配器,顾名思义,会返回一个新的迭代器,这是实现链式方法调用的关键:v.iter().map().filter()…。

与消费者适配器不同,迭代器适配器是惰性的,意味着你需要一个消费者适配器来收尾,最终将迭代器转换成一个具体的值:

let v1: Vec<i32> = vec![1, 2, 3];let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();assert_eq!(v2, vec![2, 3, 4]);

2.5.2、zip

2.5.3、filter

2.5.4、enumerate

使用 enumerate 方法可以获取迭代时的索引。
let v = vec![1u64, 2, 3, 4, 5, 6];
for (i,v) in v.iter().enumerate() {println!("第{}个值是{}",i,v)
}

2.6、自定义迭代器

自定义迭代器很简单,我们只需要实现 Iterator 特征 以及next 方法即可。实际上  Iterator 之中还有其他方法,其他方法都有默认实现,无需手动去实现。
impl Iterator for Counter {type Item = u32;fn next(&mut self) -> Option<Self::Item> {if self.count < 5 {self.count += 1;Some(self.count)} else {None}}
}

四、性能对比:循环 VS 迭代器

迭代器是 Rust的零成本抽象(zero-cost abstractions) 之一,意味着抽象并不会引入运行时开销。

总结

以上就是今天要讲的内容

http://www.mmbaike.com/news/82086.html

相关文章:

  • 中国建设银行网站官网下载安装搜索引擎bing
  • 合肥做网站123cms搜索引擎收录提交入口
  • 橙子建站广告怎么收费百度seo一本通
  • 电子商务网站开发费用今日新闻7月1日
  • 南宁做网站找哪家长春网站快速优化排名
  • 企业手机网站源码新站网站推广公司
  • 素材下载网站开发文档seo1短视频网页入口营销
  • 一个一起做网站石家庄疫情防控最新政策
  • 怎么用自己的电脑做服务器发布网站厨师培训学校
  • 东莞企业营销型网站建设网络服务商主要包括哪些
  • 戴尔电脑网站建设方案范文百度联盟怎么加入
  • 深圳网站建设培训班市场调研的方法
  • 深圳做外贸网站公司百度广告点击一次多少钱
  • 华为云怎么做网站青岛网站建设制作推广
  • 网站首页psd格式怎么做关键词完整版
  • 珠海制作公司网站搜狗网页
  • 怎么做兼职网站吗优化服务是什么意思
  • 大连网站推广爱得科技亚洲卫星电视网参数表
  • 南宁企业建站系统爱站网seo培训
  • 网络服务商是谁怎么优化关键词
  • 大型b2b电子商务平台开发苏州优化网站公司
  • 做电影网站一年赚多少钱西安优化seo托管
  • 怎么给网站带来流量产品推广平台有哪些
  • 怎么做企业网站推广赚钱nba排名赛程
  • 网站建设主流技术微信营销方式有哪些
  • 外贸网站建设哪家有名b2b平台推广网站
  • 怎样做网站宣传自己的宾馆站长工具seo综合查询5g
  • 求职网站开发360seo关键词优化
  • 郑州经纬网络做网站吗友情链接2598
  • 湖南+网站建设百度浏览器网址是多少