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特型。如果该结构体不符合这个条件,那么即使你手动添加了派生宏,也不会有效果。

相关推荐
红尘散仙几秒前
四、WebGPU 基础入门——Uniform 缓冲区与内存对齐
前端·rust·gpu
吴_知遇17 分钟前
【华为OD机试真题】428、连续字母长度 | 机试真题+思路参考+代码解析(E卷)(C++)
开发语言·c++·华为od
Java中文社群32 分钟前
最火向量数据库Milvus安装使用一条龙!
java·人工智能·后端
basketball6161 小时前
Python torchvision.transforms 下常用图像处理方法
开发语言·图像处理·python
JAVA百练成神1 小时前
深度理解spring——BeanFactory的实现
java·后端·spring
宁酱醇1 小时前
各种各样的bug合集
开发语言·笔记·python·gitlab·bug
古时的风筝1 小时前
暴论:2025年,程序员必学技能就是MCP
前端·后端·mcp
古时的风筝1 小时前
这编程圈子变化太快了,谁能告诉我 MCP 是什么
前端·后端·mcp
啊吧怪不啊吧1 小时前
Linux常见指令介绍下(入门级)
linux·开发语言·centos
谷晓光1 小时前
Python 中 `r` 前缀:字符串处理的“防转义利器”
开发语言·python