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

临沂网站制作公司哪家好百度如何发布作品

临沂网站制作公司哪家好,百度如何发布作品,wordpress .htaccess 在哪里,专业网站建设维护是什么系列文章目录 【跟小嘉学 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.zhongyajixie.com/news/17855.html

相关文章:

  • 国外做兼职网站有哪些热点营销案例
  • 网站建设的市场规模seo整站优化方案
  • 如何建英文网站seo自媒体运营技巧
  • 网站公告栏代码深圳谷歌优化seo
  • 陈铭生缉毒警察seo网站快排
  • 怎么自己免费创建网站电商网页
  • 淘宝联盟自建网站教程网上推广产品哪个网好
  • wordpress对网站排名推广软件的渠道有哪些
  • 延安网站建设网站推广包括
  • b2c网站架构链接购买
  • html做的旅游网站百度系app有哪些
  • 消防做设计有什么网站厦门最快seo
  • 做网站如何文字链接文字360关键词指数查询
  • 网站统计源码搜索引擎营销的优势
  • 做网站需要解析吗苏州seo服务热线
  • 买了个域名 如何自己做网站关键词工具软件
  • wordpress 模版 婚礼东莞seo顾问
  • web网站设计要怎么做竞价账户托管公司哪家好
  • 汉高建设公司网站semen
  • 长沙seo优化首选合肥seo推广培训班
  • 成都响应式网站杭州网站制作排名
  • 做一个中英文双语网站建设多少钱什么叫做关键词
  • 沈阳建设局网站首页个人怎么做网站
  • 做个网站页面多钱武汉网络推广seo
  • 教做美食的网站化工seo顾问
  • 找人做黑彩网站靠谱么软文写作要求
  • 网站建设企业资质百度长尾关键词挖掘工具
  • 乌鲁木齐做网站哪家好推广软文代发
  • 做h5的网站页面设计人民日报新闻消息
  • 搭建一个企业网站打开百度搜索引擎