Rust常用特型之Default特型

在Rust标准库中,存在很多常用的工具类特型,它们能帮助我们写出更具有Rust风格的代码。

某些类型可以有一个有意义的默认值,例如默认的向量或者字符串是空的,默认的数字为0,默认的Option是None等。

这样的类型可以实现std::default::Default特型:

rust 复制代码
trait Default {
fn default() -> Self;
}

该特型很简单,就只有一个关联函数default,用于返回自身类型的一个新的值。

我们来看字符串String对该特型的实现,非常简单:

rust 复制代码
impl Default for String {
fn default() -> String {
  String::new()
  }
}

所以字符串的默认值就是一个新的空字符串.所有Rust的集合类型,Vec,HashMap,BinaryHeap等,都实现了Default特型,它们的default函数返回一个空的集合。这在你需要先建立一个集合,以后再向里面插入值时非常有用,因为你建立集合时不需要指定其中元素的类型,在第一次插入值时决定。

例如 Iterator特型的partition函数 把迭代器产生的值分离成两个集合,它使用一个闭包函数来决定哪个值去哪个集合。

rust 复制代码
use std::collections::HashSet;
let squares = [4, 9, 16, 25, 36, 49, 64];
let (powers_of_two, impure): (HashSet<i32>, HashSet<i32>)
  = squares.iter().partition(|&n| n & (n-1) == 0);
assert_eq!(powers_of_two.len(), 3);
assert_eq!(impure.len(), 4);

闭包函数使用位操作符来查找哪些数是2的幂,partition函数使用它产生两个HashSet。当然,partition函数并不是只能产生HashSet,你可以使用它产生任何类型的集合,只要该集合实现了DefaultExtend<T>特型,前者它会产生一个新的空集合,后者是将产生的值添加到集合中去。String 也实现了DefaultExtend<char>特型,因此你可以这样写:

rust 复制代码
let (upper, lower): (String, String)
  = "Great Teacher Onizuka".chars().partition(|&c|c.is_uppercase());
assert_eq!(upper, "GTO");
assert_eq!(lower, "reat eacher nizuka");

Default特型另一个常见的应用场景为多字段结构体赋值。如果一个结构体有很多字段,但是其中绝大多数字段的值是固定的,很少变化的。因此我们构造结构体时只需要给出少数几个需要设定的字段就行了,其它的固定字段使用一个默认值就行。例如glimu::DrawParameters结构体有24个字段,每个字段都用来控制OpenGL怎么渲染图形中的某些位。而glium draw函数使用一个DrawParameters 结构体作为参数,由于它实现了Default,你可以这样写:

rust 复制代码
let params = glium::DrawParameters {
    line_width: Some(0.02),
    point_size: Some(0.02),
    .. Default::default()
};
target.draw(..., &params).unwrap();

这里我们只需要写出该结构体的两个字段 line_width和point_size,其它的都使用默认值。Default::default()会创建一个包含默认初始化值的DrawParameters结构体(这里为什么创建的值的类型是DrawParameters?因为Rust会自动推断,当然你也可以写 DrawParameters::default(),这样会多拼几个字母)。..语法是解构,和Javascript类似,就是余下的字段全部从这里获取,但是有一眯注意,它必须出现在结构体构造的最后一行(Javascript没有这个限制)。

如果一个T类型实现了Default,Rust 标准库也为Rc<T>,Arc<T>Box<T>, Cell<T>, RefCell<T>, Cow<T>, Mutex<T>

RwLock<T>自动实现了Default特型。例如,Rc<T>的默认值就是一个指向T默认值的Rc指针。如果元组的所有元素实现了Default,那么该元组(tuple)也自动实现了Default特型。它的默认值就是一个容纳了每个元素默认值的元组。

Rust 并没有为结构体自动实现Default特型。但是如果结构体所有的字段都实现了Default,那么你可以简单的在结构体定义上面添加#derive(Default)]来为该结构体自动实现Default特型。如果该结构体不符合这个条件,那么即使你手动添加了派生宏,也不会有效果。

相关推荐
Dxy12393102164 小时前
Python 使用正则表达式将多个空格替换为一个空格
开发语言·python·正则表达式
我学上瘾了4 小时前
Spring Cloud的前世今生
后端·spring·spring cloud
波波0075 小时前
ASP.NET Core 健康检查实战:不只是一个 /health 接口
后端·asp.net
小码哥_常5 小时前
Spring Boot 搭建邮件发送系统:开启你的邮件自动化之旅
后端
故事和你915 小时前
洛谷-数据结构1-1-线性表1
开发语言·数据结构·c++·算法·leetcode·动态规划·图论
石榴树下的七彩鱼6 小时前
图片修复 API 接入实战:网站如何自动去除图片水印(Python / PHP / C# 示例)
图像处理·后端·python·c#·php·api·图片去水印
我叫黑大帅6 小时前
为什么TCP是三次握手?
后端·网络协议·面试
我叫黑大帅6 小时前
如何排查 MySQL 慢查询
后端·sql·面试
techdashen6 小时前
Rust项目公开征测:Cargo 构建目录新布局方案
开发语言·后端·rust
星空椰6 小时前
JavaScript 进阶基础:函数、作用域与常用技巧总结
开发语言·前端·javascript