引言

设计模式

在开发程序中,我们必须解决许多问题。一个程序可以看作是一个问题的解决方案。它也可以被看作是许多不同问题的解决方案的集合。所有这些解决方案共同解决一个更大的问题。

在Rust中的设计模式

有许多问题的形式是相同的,由于事实上,rust不是面向对象设计,模式不同于其他面向对象程序设计语言,虽然细节是不同的,因为他们有相同的形式,他们可以解决使用相同的基本方法。

设计模式是解决编写软件时常见问题的方法。

反模式是解决这些相同问题的方法。

然而,尽管设计模式给我们带来了好处,反模式却带来了更多的问题。

惯用法,是编码是要遵守的指南,他们是社区的社区规范,你可以破他们,但如果你这样做,你应该有一个很好的理由。

TODO: 说明为什么Rust是一个有点特殊功能要素,类型系统,借用检查。

Idioms

惯用法是一种常用的风格和模式,在很大程度上得到了社区的认可,他们是指导方针,编写惯用代码可以让其他开发人员理解正在发生的事情,因为他们熟悉代码的形式。

计算机理解编译器生成的机器代码,因此,这种语言对开发人员来说是最有利的,所以既然我们有了这个抽象层,为什么不好好利用它,然它变得简单呢?

记住KISS原则,"保持简单,Stupid。" 他声称“大多数系统如果有保持简单而不是复杂,就能工作的最好,因此,简单应该是设计的一个关键目标,应该避免不必要的复杂性。

代码是给人类而不是计算机去理解的。

Use borrowed types for arguments

对参数使用borrowed types

描述

当你决定使用哪种参数作为函数参数时,使用强制解引用(deref coerrcion) 的目标可以增加代码的灵活性。这样,函数将接受更多的输入类型。

这不经限于可切片类型或者胖指针类型。事实上,你总是更喜欢borrowed type 而不是 borrowing the owned type, 例如, &str Over &String, &[T] Over &Vec<T>, or &T Over &Box<T>

对于owned type 已经提供了间接层的实例,使用borrowed type可以避免使用间接层。例如,String有一个间接层,因此&String将有两个间接层。我们可以通过使用&str来避免这种情况,并且在调用函数时让&String强制转换到&str.

例子

在本例中,我们将说明使用&String作为函数参数与使用&str的区别。但是这些思想也适用于使用&Vec <T> 与使用&[T] 或者使用&T 与&Box<T> .

考虑一个例子,我们希望确定一个单词是否包含三个连续的元音,我们不需要拥有字符串来确定这一点。因为我们将采用一个引用。

代码可能是这样的

fn three_vowels(word: &String) -> bool {
let mut vowel_ocunt = 0;
for c in word.chars() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' => {
vowel_count += 1;
if vowel_count >= 3 {
return true;
}
}
_ => vowel_count = 0;
}
}
false
}
fn main() {
let ferris = "Ferris".to_string();
let curious = "Curious".to_string();
println!("{}: {}", ferris, three_vowels(&ferris));
println!("{}: {}", curious, three_vowels(&curious)); // This work fine,but the following two lines would fail;
// println!("Ferris: {}", three_vowles("Ferris"));
// println!("Currious: {}", three_vowles("Curious"));
}

这样做很好,因为我们将&String类型作为参数传递。我们在最后两行中进行注释,这个示例就会失败,因为&str类型不会强制转换为&String。我们可以通过简单地修改参数的类型来解决这个问题。

例如,我们将函数声明更改为

fn three_vowels(word: &str) -> bool {

然后两个版本将编译并打印相同的输出

Ferris: false
Curious: true

但是,等等,这还不是全部。这个故事还有更多内容。很可能你会对自己说:这不重要,我们永远不会使用&' static str作为输入方式(就像我们使用"Ferris"时所作的那样)。即使忽略这个特殊的示例,您可能仍然会发现使用&str比使用&String更具灵活性.

现在让我们举一个例子,有人给我们一个句子,我们想确定句子中的任何一个单词是否有一个包含三个连续元音的单词,我们可能应该利用我们已经定义的函数,简单的输入句子中的每个单词。

下面试一个例子:

fn three_vowels(word: &String) -> bool {
let mut vowel_ocunt = 0;
for c in word.chars() {
match c {
'a' | 'e' | 'i' | 'o' | 'u' => {
vowel_count += 1;
if vowel_count >= 3 {
return true;
}
}
_ => vowel_count = 0;
}
}
false
}
fn main() {
let sentence_string = "Once upon a time, there was a friendly curious crab named Ferris".to_string();
for word in sentence_string.split(' ') {
if three_vowels(word) {
println!("{} has three consecutive vowels!", word);
}
}
}

带有&str类型参数声明的函数运行这个例子将产生

curious has three consecutive vowels!

但是,我们的函数使用&String类型的参数声明时,这个示例将不会运行。这是因为字符串切片是&str而不是&String,需要分配内存将&str转换为&String,但是这不是隐式的,而从String转换为&str是廉价且隐式的。

参见

原文: Rust Design Patterns

(翻译)Rust中的设计模式(1-Use borrowed types for arguments)的更多相关文章

  1. 【翻译】R 中的设计模式

    目录 R 中的设计模式 不动点算法 包装器模式 接口模式 柯里化(Currying) 闭包(Closures) 缓存模式 计数器模式 R 中的设计模式 本文翻译自 Design Patterns in ...

  2. Rust中的RefCell和内部可变性

    RefCell Rust在编译阶段会进行严格的借用规则检查,规则如下: 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用. 引用必须总是有效. 即在编译阶段,当有一个不可变值时,不能可 ...

  3. 【译】理解Rust中的闭包

    原文标题:Understanding Closures in Rust 原文链接:https://medium.com/swlh/understanding-closures-in-rust-21f2 ...

  4. 【译】深入理解Rust中的生命周期

    原文标题:Understanding Rust Lifetimes 原文链接:https://medium.com/nearprotocol/understanding-rust-lifetimes- ...

  5. 【原创翻译】认识MVC设计模式:web应用开发的基础(实际编码篇)

    原文地址:http://www.larryullman.com/2009/10/15/understanding-mvc-part-3/ 全系列INDEX [原创翻译]认识MVC设计模式:web应用开 ...

  6. 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?

    我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...

  7. 【译】Rust中的array、vector和slice

    原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...

  8. 【译】理解Rust中的局部移动

    原文标题:Understanding Partial Moves in Rust 原文链接:https://whileydave.com/2020/11/30/understanding-partia ...

  9. 【译】理解Rust中的Futures (一)

    原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...

  10. 【译】理解Rust中的Futures(二)

    原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...

随机推荐

  1. vue中 computed和watch的一些简单理解(区别)

    今天看到一个问题,就是vue的computed和watch要在哪些场景下使用,其实也就是在问他们的区别.computed也就是计算属性,它可以帮助我们将在模板中的一些稍微复杂的逻辑计算放回到js代码中 ...

  2. 集合-TreeMap源码分析

    一.简介 TreeMap最早出现在JDK 1.2中,是 Java 集合框架中比较重要一个的实现.TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey.get ...

  3. '林子雨大数据' 实验3 HBase操作与接口编程

    "林子雨大数据" 实验3 HBase操作与接口编程 环境搭建 VM虚拟机和Ubuntu系统的安装 在Windows中使用VirtualBox安装Ubuntu虚拟机(2020年7月版 ...

  4. WPF 界面布局、常用控件入门教程实例 WPF入门学习控件快速教程例子 WPF上位机、工控串口通信经典入门

    WPF(Windows Presentation Foundation)是一种用于创建 Windows 桌面应用程序的框架,它提供了丰富的控件库和灵活的界面布局,可以创建现代化的用户界面.下面是 WP ...

  5. layUI之树状表格异步加载组件treetableAsync.js(基于treetable.js)

    目录 概述 1. 使用说明 2. 使用需知 2.1 本组件依赖于treetable.js[重中之重] 2.2 本组件基于layUIAdmin进行使用 2.3 本组件的方法支持treetable.js的 ...

  6. redis 基于 漏斗算法 实现对 api 的限流

    漏斗算法 漏桶算法的原理: 漏桶有一定的容量,给漏桶注水,当单位时间内注入水量大于流出水量,漏桶内积累的水就会越来越多,直到溢出. 就好比大批量请求访问nginx相当于注水,nginx根据配置按照固定 ...

  7. Yii2批量插入数据

    方法一 yii2一次插入多行数据  /** * @inheritdoc 批量添加 * @params $add array 添加数据 */ public function add_all($add) ...

  8. Redis(四)主从复制

    主从复制 简介 主机数据更新之后根据配置和策略,自动同步数据到备机的Master/Slaver机制,Master以写为主,Slaver以读为主. 这样的机制能够实现: 读写分离:Master以写为主, ...

  9. 使用Jmeter进行CPU、内存等监控

    一.需要的准备 1.jp@gc - PerfMon Metrics Collector插件(安装方法就不过多介绍啦!) 2.ServerAgent服务器(下载:https://github.com/u ...

  10. MySQL之主从复制搭建

    文章目录 主从复制 主从搭建 配置主从复制的命令 测试 总结 主从复制 主从也叫做(AB复制),允许一个服务器从一个服务器数据库(主服务器)的数据复制到一个或者多个MySQL数据库服务器. 主从复制的 ...