【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数

简介: 【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档



前言

Rust 不是传统的面向对象编程语言,它的所有特性,使其独一无二。因此,学习特定于Rust的设计模式是必要的。本系列文章为作者学习《Rust设计模式》的学习笔记以及自己的见解。因此,本系列文章的结构也与此书的结构相同(后续可能会调成结构),基本上分为三个部分

  1. 习惯语法
  2. 设计模式
  3. 反模式(anti_patterns)

习惯语法是社区广泛认同的Rust编程常用风格、指导方针和模式。编写惯用的代码可以让其他开发人员更好地理解你所写的代码。

本期文章是该系列文章的开篇内容,从Rust的惯用程序设计手法来入门学习,与设计模式的书所对应,即本期主题为

  1. 使用借用类型作为参数
  2. 格式化字符串
  3. 构造函数

一、使用借用类型作为参数

使用借用类型作为参数可以避免函数传参过程中的间接层,就比如String有一个间接层,&String就有两个间接层,我们可以通过使用&str来避免这种情况,并让&String在调用函数时强制转换为&str。

在本例中,我们使用&String来作为函数参数与&str进行对比。

这种情况在 &Vec<T>&[T] 或者 &Box<T>&T 上也适用。

借用书中的例子,比如说我们想要判断一个单词中是否有三个元音,我们使用&String作为参数传入,代码就应该写成下面这样

元音:a e i o u

fn three_vowels(word: &String) -> bool {
    let mut vowel_count = 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));
    // 上面这么写是没有问题的,但是如果写成下面注释里面的样子,就会报错
    // println!("Ferris: {}", three_vowels("Ferris"));
    // println!("Curious: {}", three_vowels("Curious"));
}

这种情况在C++里面也是十分常见的,因为函数签名里面传入的参数类型应该是&String,如果直接传入"Ferris",则是&str,它在传入函数中的时候,不会强制转化为&String,这点学习C++的朋友一定特别熟悉,如果要使之可以那样传参,那么函数签名就得这么改

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

这样不论我们传的是哪种参数,就都会输出正常的结果

Ferris: false
Curious: true

现在我们尝试这样一个例子,给出一个句子,判断其中每一个单词,是否有三个联系的元音字母,为此,我们把代码改成如下的样子

fn three_vowels(word: &str) -> bool {
    let mut vowel_count = 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!("{} 有三个连续的元音!", word);
        }
    }
}

可以看到,three_vowels函数我们并未改变,而是在调用函数的地方,使用split方法,将字符串分割为多个单词,依次传入函数,此时就体现出&str的好处了,split返回的数组中的元素都是&str类型的。而String类型转&str就很简便。

二、格式化拼接字符串

一般来说,我们在开发的时候,做字符串拼接会使用String方法的push和push_str方法,或者直接就用+来实现字符串的拼接,但是有时候使用format!可能会更加的方便,特别是混合了各种类型的东西的字符串。

首先我们手动的构建一个字符串

let mut hello = "Hello ".to_owned();
hello.push_str(name);
hello.push('!');

这是相当常见的一种用法,现在我们使用格式化的方式来构建这个字符串

fn say_hello(name: &str) -> String {
    format!("Hello {}!", name)
}

format!返回一个格式化的字符串,{}作为占位符,然后后面传入参数,就可以返回处理好的字符串了,在这么一个简单的地方难以看出他的好处,但是当插入的东西比较多的时候就知道格式化字符串的好处了。

这一块在python和js中都有类似的东西,我觉得还是python和js里面的好用在js里面只需要

let hello = `hello ${name}`

在Rust中,使用format!来格式化拼接字符串是最简洁、可读性最好的方法。

三、使用构造函数

在Rust中实际上是没有构造函数这个概念的,但是可以使用一个约定俗成的关联函数new来创建一个对象。就比如

pub struct Second {
    value: u64
}
impl Second {
    // 构建一个Second实例
    // 注意,这是个关联函数,参数里面没有self
    pub fn new(value: u64) -> Self {
        Self { value }
    }
    /// 返回秒数,即Second的value
    pub fn value(&self) -> u64 {
        self.value
    }
}

我们创建了个Second 结构体,并且实现了new方法来构建一个新的对象。

在使用的时候,我们调用new方法就可以创建一个对象了

let s = Second::new(42);

Rust中还可以实现Default特质来实现默认的构造方法

impl Default for Second {
    fn default() -> Self {
        Self { value: 0 }
    }
}

使用derive派生Default也能起到同样的效果,比如你可以这么写

#[derive(Default)]
pub struct Second {
    value: u64
}
impl Second {
    pub fn value(&self) -> u64 {
        self.value
    }
}

此时我们不用new方法了,可以直接调用default方法来构建实例

let s = Second::default();

注意: 这里更推荐你使用new来创建构造方法,在社区的开发中,通常会使用new来实现构造方法,因为它比起default更加合理,也更加符合阅读习惯,他的功能的default是一样的。


总结

本节内容为Rust设计模式的第一期,主要为大家引入了Rust设计模式的一些惯用语法,学习了

  • 使用借用类型作为函数参数
  • 格式化拼接字符串
  • 构造函数

相信通过本系列文章,你可以对Rust有更加深入的理解。


本人创建了一起学Rust社区,欢迎各位对rust感兴趣的朋友加入

http://t.csdn.cn/AsEZ9
目录
相关文章
|
7月前
|
Rust 安全 编译器
Rust中的生命周期与借用检查器:内存安全的守护神
本文深入探讨了Rust编程语言中生命周期与借用检查器的概念及其工作原理。Rust通过这些机制,在编译时确保了内存安全,避免了数据竞争和悬挂指针等常见问题。我们将详细解释生命周期如何管理数据的存活期,以及借用检查器如何确保数据的独占或共享访问,从而在不牺牲性能的前提下,为开发者提供了强大的内存安全保障。
|
7月前
|
存储 Rust 程序员
【一起学Rust | 基础篇 | rust新特性】Rust 1.65.0——泛型关联类型、let-else语句
【一起学Rust | 基础篇 | rust新特性】Rust 1.65.0——泛型关联类型、let-else语句
108 0
|
3月前
|
Rust 开发者 索引
30天拿下Rust之命令行参数
30天拿下Rust之命令行参数
58 0
|
2月前
|
Rust API
【Rust学习】09_方法语法
结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。在 impl 块中,你可以定义与你的类型相关联的函数,而方法是一种相关联的函数,允许您指定结构体的实例具有的行为。 但是结构体并不是创建自定义类型的唯一方式:让我们转向 Rust 的 enum 功能,将另一个工具添加到你的工具箱中。
20 0
|
3月前
|
设计模式 Rust 安全
30天拿下Rust之高级类型
30天拿下Rust之高级类型
26 0
|
4月前
|
Rust 安全 编译器
30天拿下Rust之语法大全
Rust是一种系统级编程语言,以其独特的所有权系统和内存安全性受到开发者青睐。本文从基本数据类型入手,介绍了标量类型如整数、浮点数、布尔值及字符,复合类型如元组、数组和结构体等。此外,还探讨了变量与常量的声明与使用,条件判断与循环语句的语法,以及函数定义与调用的方法。文章通过示例代码展示了如何使用Rust编写简洁高效的程序,并简要介绍了注释与宏的概念,为读者快速掌握这门语言提供了实用指南。欲获取最新文章或交流技术问题,请关注微信公众号“希望睿智”。
58 1
|
5月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 构造函数模式
js设计模式【详解】—— 构造函数模式
49 6
|
5月前
|
Rust 安全 程序员
Rust与C++的区别及使用问题之Rust解决多线程下的共享的问题如何解决
Rust与C++的区别及使用问题之Rust解决多线程下的共享的问题如何解决
|
5月前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
52 0
|
5月前
|
Rust
Rust 中使用 :: 这种语法的几种情况
Rust 中使用 :: 这种语法的几种情况