引言

设计模式

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

在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. 鸿蒙开发学习笔记-UIAbility-Router页面跳转接口源码分析

    在鸿蒙开发中,UIAbility的跳转使用 router 方法. 在使用的时候需导入 import router from '@ohos.router'; 该方法接口成员如下: 1.interface ...

  2. 【原理揭秘】Vite 是怎么兼容老旧浏览器的?你以为仅仅依靠 Babel?

    作者:京东科技 孙凯 一.前言 对前端开发者来说,Vite 应该不算陌生了,它是一款基于 nobundle 和 bundleless 思想诞生的前端开发与构建工具,官网对它的概括和期待只有一句话:&q ...

  3. .net6的IIS发布部署

    1.打开控制面板,打开程序 2.点击启动或关闭windows功能 3.在其中选择要设置的IIS功能 4.重启IIS服务 5.发布项目 6.在开始菜单搜索IIS,点击IIS管理器 7.右击网站,点击添加 ...

  4. [ORACLE]Oracle客户端SQLPlus安装与运用

    简述 sqlplus :oracle公司提供用户操作oracle数据库的工具. sqlplus是oracle原始数据操作的客户端,这种命令行的格式有着强大的逻辑性,如果经常使用会对数据库的理解加深很多 ...

  5. [Linux/Java SE]查看JAR包内的类 | JAR 命令 | 反编译

    1 查看JAR包内的类 另一个思路: 解压JAR包jar -xf <jarPath> 1-1 单JAR包 -t list table of contents for archive(列出存 ...

  6. 深入理解 python 虚拟机:字节码教程(1)——原来装饰器是这样实现的

    深入理解 python 虚拟机:字节码教程(1)--原来装饰器是这样实现的 在本篇文章当中主要给大家介绍在 cpython 当中一些比较常见的字节码,从根本上理解 python 程序的执行.在本文当中 ...

  7. 从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(二)

    传送门:从0到1手把手教你ASP.NET Core Web API项目配置接口文档Swagger(一) 一.设置Swagger页面为首页--开发环境 我们虽然可以在输入 /swagger 后顺利的访问 ...

  8. Redis缓冲区溢出及解决方案

    缓冲区(buffer),是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区. 一.Redis缓冲区溢出影响 在Redis ...

  9. Kubernetes集群调度增强之超容量扩容

    作者:京东科技 徐宪章 1 什么是超容量扩容 超容量扩容功能,是指预先调度一定数量的工作节点,当业务高峰期或者集群整体负载较高时,可以使应用不必等待集群工作节点扩容,从而迅速完成应用横向扩容.通常情况 ...

  10. MINIO使用

    1.作用 官网地址:https://docs.min.io/ 文件存储.文件对象的上传.下载和删除! 2.使用依赖 <dependency> <groupId>io.minio ...