(翻译)Rust中的设计模式(1-Use borrowed types for arguments)
引言
设计模式
在开发程序中,我们必须解决许多问题。一个程序可以看作是一个问题的解决方案。它也可以被看作是许多不同问题的解决方案的集合。所有这些解决方案共同解决一个更大的问题。
在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 Language Reference on Type Coercions
- For more discussion on how to handle
String
and&str
see this blog series (2015) by Herman J. Radtke III.
(翻译)Rust中的设计模式(1-Use borrowed types for arguments)的更多相关文章
- 【翻译】R 中的设计模式
目录 R 中的设计模式 不动点算法 包装器模式 接口模式 柯里化(Currying) 闭包(Closures) 缓存模式 计数器模式 R 中的设计模式 本文翻译自 Design Patterns in ...
- Rust中的RefCell和内部可变性
RefCell Rust在编译阶段会进行严格的借用规则检查,规则如下: 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用. 引用必须总是有效. 即在编译阶段,当有一个不可变值时,不能可 ...
- 【译】理解Rust中的闭包
原文标题:Understanding Closures in Rust 原文链接:https://medium.com/swlh/understanding-closures-in-rust-21f2 ...
- 【译】深入理解Rust中的生命周期
原文标题:Understanding Rust Lifetimes 原文链接:https://medium.com/nearprotocol/understanding-rust-lifetimes- ...
- 【原创翻译】认识MVC设计模式:web应用开发的基础(实际编码篇)
原文地址:http://www.larryullman.com/2009/10/15/understanding-mvc-part-3/ 全系列INDEX [原创翻译]认识MVC设计模式:web应用开 ...
- 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?
我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...
- 【译】Rust中的array、vector和slice
原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...
- 【译】理解Rust中的局部移动
原文标题:Understanding Partial Moves in Rust 原文链接:https://whileydave.com/2020/11/30/understanding-partia ...
- 【译】理解Rust中的Futures (一)
原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...
- 【译】理解Rust中的Futures(二)
原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...
随机推荐
- active
rabbitMQ与activeMQ区别 之前的项目中都用到了这两个消息队列 ActiveMq,传统的消息队列,使用Java语言编写.基于JMS(Java Message Service),采用多线程并 ...
- selenium之文件的上传
文件的上传:主要是两种实现方法: 1.如果定位的元素是type类型是file类型的话,那么直接定位元素并使用send_keys方法完成文件上传 2.如果是非file类型的话,则需要使用第三方工具完成文 ...
- 股票K线图概要——R语言
K线图是200多年前日本人发明的,后来传入了美国.K线图本来就是对当前数据的可视化显示而已,但是越来越多的人对K线图做出了痴迷的分析和解读,有众多追随者也根据K线图指导自己的具体行动,因此,K线图在实 ...
- AtCoder Beginner Contest 236 E - Average and Median
给定一个序列,要求相邻两个数至少选一个,求选出数的最大平均数和最大中位数 \(\text{sol}\):二分答案. 二分平均数\(\text{mid}\),将每个元素减去\(\text{mid}\), ...
- 介绍一下js垃圾回收机制
JavaScript中的垃圾回收机制负责自动管理内存,回收不再使用的对象所占用的内存空间.在JavaScript中,开发者不需要显式地分配和释放内存,垃圾回收器会自动完成这些操作.以下是关于JavaS ...
- MySQL InnoDB Architecture 简要介绍
MySQL InnoDB 存储引擎整体架构图: 一.内存存储结构 1.Buffer Pool buffer pool 是主内存中的一块儿存储区域,用于存储访问的表及索引数据.这样从内存中直接访问获取使 ...
- 龙芯(Loongarch64),在Linux虚拟一个龙芯OS体验下
前言 想体验下龙芯OS,但是又没有龙芯开发板或者龙芯实体机.手头上只有一个X64环境的Linux发行版,应该怎么做呢? 概括 其实非常简单,可以通过Chroot命令和Qemu在X64的指令集系统上模拟 ...
- ROS机器人校正
vROS机器人IMU自动校正 连接小车 注意:必须在同一区域网 ssh clbrobort@clbrobort 激活树莓派主板 roslaunch clbrobot bringup.launch 自动 ...
- Network Science:巴拉巴西网络科学学习笔记3——第二章随机网络
第二章:随机网络Erdős-Rényi Network (ER网络) 随机网络的两种定义形式: \(G(N,L)\)模型:N个节点,L条边随机链接. \(G(N,p)\)模型:N个节点,每个节点之间以 ...
- mybatis中useGeneratedKeys用法--插入数据库后获取主键值
前言:今天无意在mapper文件中看到useGeneratedKeys这个词,好奇就查了下,发现能解决我之前插入有外键表数据时,这个外键获取繁琐的问题,于是学习敲DEMO记录 在项目中经常需要获 ...