Rust Newtype模式(通过结构体封装现有类型来创建新的类型)(单字段结构体,通过.0访问)模式匹配、解构、DerefMut

news2024/11/27 5:17:07

文章目录

  • 深入理解Rust中的Newtype模式
    • 什么是Newtype模式?
      • Newtype模式的基本形式
      • Newtype的访问
        • 访问 Newtype 的值
          • 1. 通过 `.0` 访问字段
          • 2. 通过方法访问
          • 3. 通过模式匹配(解构)访问
        • 总结
    • Newtype模式的应用场景
      • 1. 类型安全
      • 2. 增强可读性
      • 3. 定制化实现(比如添加方法或实现trait)
    • Newtype模式的优势
      • 1. 类型安全
      • 2. 更好的API设计
      • 3. 继承标准库功能
      • 4. 可维护性
    • Newtype模式的缺点
      • 1. 性能开销
      • 2. 增加的复杂性
    • Newtype模式与其它Rust特性结合
      • 示例:使用`Deref`和`DerefMut`
    • 小结

深入理解Rust中的Newtype模式

Rust是一种现代系统编程语言,它提供了许多创新的特性来帮助开发者编写高效、安全的代码。Newtype模式是Rust中的一个重要概念,广泛用于封装和类型安全的场景中。本文将通过深入剖析Rust中的Newtype模式,探讨其优势与实际应用。

什么是Newtype模式?

Newtype模式是一种通过结构体封装现有类型来创建新的类型的编程模式。简单来说,Newtype模式就是将一个已有类型包装在一个新的结构体中,从而创建一个新的类型。这个新类型与原类型在功能上等效,但在类型系统上它们是不同的,具备类型安全的优势。

Newtype模式的基本形式

在Rust中,Newtype模式通常是通过定义一个新的结构体来实现的。例如:

struct Meter(i32);

这里,Meter是一个新类型,它封装了一个i32类型的值。尽管它只是一个整数,但由于它是一个新类型,它与i32类型在类型系统上是不同的。

Newtype的访问

在 Rust 中,访问 Newtype 类型的值与访问普通结构体的字段类似,但是需要通过访问其封装的单一字段来进行。由于 Newtype 本质上是一个单字段结构体,可以通过解构或直接访问该字段来操作其中的值。

访问 Newtype 的值

可以通过以下两种方式来访问 MyInteger 内部的值:

1. 通过 .0 访问字段
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!

// #[derive(Debug)]

struct MyInteger(i32);

impl MyInteger {
    fn new(value: i32) -> MyInteger {
        MyInteger(value)
    }
}

fn main() {
    let x = MyInteger::new(10);
    println!("The value is: {}", x.0); // 直接访问内部字段
}

在这里插入图片描述

输出:

The value is: 10
2. 通过方法访问

如果你定义了方法来访问 Newtype 的内部字段,可以通过方法来访问值:

#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!

// #[derive(Debug)]

struct MyInteger(i32);

impl MyInteger {
    fn new(value: i32) -> MyInteger {
        MyInteger(value)
    }

    fn value(&self) -> i32 {
        self.0
    }
}

fn main() {
    let x = MyInteger::new(10);
    println!("The value is: {}", x.value());
}

fn main() {
    let x = MyInteger::new(10);
    println!("The value is: {}", x.value());
}

在这里插入图片描述

输出:

The value is: 10
3. 通过模式匹配(解构)访问

你也可以通过模式匹配来解构 Newtype 并访问其中的值:

#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!

// #[derive(Debug)]

struct MyInteger(i32);

impl MyInteger {
    fn new(value: i32) -> MyInteger {
        MyInteger(value)
    }
}

fn main() {
    let x = MyInteger::new(10);

    // 解构并获取内部的值
    let MyInteger(inner) = x;
    println!("The value is: {}", inner);
}

输出:

The value is: 10

在这里插入图片描述

总结
  • 访问 Newtype 类型的内部值,可以通过 my_newtype.0 来直接访问其封装的字段。
  • 你还可以定义额外的方法(如 value)来封装访问逻辑。
  • 使用模式匹配进行解构也是一种访问 Newtype 值的有效方法。

Newtype模式的应用场景

1. 类型安全

通过Newtype模式,可以在不同类型之间建立明确的区分,即使它们底层存储的是相同的值。这种封装可以帮助开发者避免类型混淆或错误使用。比如,可以避免将长度单位错误地与重量单位混合使用。

struct Meter(i32);
struct Kilogram(i32);

fn add_length(m1: Meter, m2: Meter) -> Meter {
    Meter(m1.0 + m2.0)
}

fn add_weight(k1: Kilogram, k2: Kilogram) -> Kilogram {
    Kilogram(k1.0 + k2.0)
}

在这个例子中,MeterKilogram虽然都存储一个i32值,但它们是完全不同的类型,因此不能被混用。这种类型安全可以防止错误的加法操作。

2. 增强可读性

Newtype模式能使代码更加语义化,增加可读性。通过使用具有描述性名称的结构体,可以明确标识变量的用途和含义,而不仅仅依赖于类型本身。例如:

struct UserId(i32);
struct OrderId(i32);

这里,UserIdOrderId显然是不同的逻辑概念,即使它们背后都是i32类型的整数。

3. 定制化实现(比如添加方法或实现trait)

通过Newtype模式,可以为封装的类型实现更多的功能或行为,甚至在标准库中的类型上进行定制。例如,添加方法或实现trait。

struct Celsius(f64);
struct Fahrenheit(f64);

impl Celsius {
    fn to_fahrenheit(&self) -> Fahrenheit {
        Fahrenheit(self.0 * 9.0 / 5.0 + 32.0)
    }
}

impl Fahrenheit {
    fn to_celsius(&self) -> Celsius {
        Celsius((self.0 - 32.0) * 5.0 / 9.0)
    }
}

在这个例子中,CelsiusFahrenheit是分别封装了摄氏度和华氏度的Newtype类型,且它们各自实现了转换的方法,使得类型转换更加明确和安全。

Newtype模式的优势

1. 类型安全

Newtype模式通过创建新的类型,确保不同概念的数据不会混淆。这不仅增强了程序的类型安全性,也帮助开发者更好地表达代码中的意图。

2. 更好的API设计

通过Newtype封装,API可以更加简洁且富有表现力。例如,不同的计量单位(长度、质量等)可以通过封装来设计,避免了接口中传递原始数据类型。

3. 继承标准库功能

Newtype模式允许在新的类型上实现标准库的功能。这使得新类型既能够发挥底层类型的优势,又能具备额外的定制化行为。

4. 可维护性

Newtype模式帮助开发者更好地管理复杂的类型系统。当项目规模扩大时,保持清晰的类型定义和强类型检查,能够减少潜在的错误,提高代码的可维护性。

Newtype模式的缺点

1. 性能开销

虽然Newtype模式通常不会引入显著的性能损失,但它确实会带来一些额外的封装开销。例如,使用Newtype类型时,可能需要进行类型拆包操作,这可能会影响性能。

2. 增加的复杂性

过多的类型封装可能导致类型系统的过度复杂化,尤其是对于初学者或快速开发的场景。过多的Newtype类型可能使得理解和维护代码变得困难。

Newtype模式与其它Rust特性结合

Rust的许多特性可以与Newtype模式结合使用,从而增强代码的灵活性和功能。例如,DerefDerefMut trait可以让封装类型直接访问底层类型的功能,FromInto trait可以简化类型转换。

示例:使用DerefDerefMut

#![allow(dead_code)] // 忽略全局dead code,放在模块开头!
#![allow(unused_variables)] // 忽略未使用变量,放在模块开头!

// #[derive(Debug)]

use std::ops::{Deref, DerefMut};

struct Meter(i32);

impl Deref for Meter {
    type Target = i32;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Meter {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main() {
    let mut meter = Meter(10);

    // 使用 Deref trait,自动解引用
    println!("Meter value: {}", *meter);

    // 使用 DerefMut trait,修改值
    *meter = 20;
    println!("Updated Meter value: {}", *meter);
}

在这里插入图片描述

这里,通过实现DerefDerefMut,我们可以直接访问Meter中的i32值,而无需显式拆包。这为封装的类型提供了更加灵活的使用方式。

小结

Newtype模式在Rust中是一种非常有用的设计模式,它为开发者提供了类型安全、增强可读性、定制化实现等多重优势。通过使用Newtype模式,可以确保代码的类型正确性,并使得API更加清晰易懂。在实际开发中,合理地使用Newtype模式可以提升代码质量和可维护性,尤其是在处理复杂类型和多种不同数据单元的场景中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2248187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络层协议IP

对于网络层我们直接通过IP协议来了解其内容 一.IP协议 首先我们先来了解几个概念: 主机:配有IP地址,但是不进行路由控制的设备 路由器:配有IP地址,同时进行路由控制的设备 节点:主机和路由器的统称 所以现在…

Qt界面篇:QMessageBox高级用法

1、演示效果 2、用法注意 2.1 设置图标 用于显示实际图标的pixmap取决于当前的GUI样式。也可以通过设置icon pixmap属性为图标设置自定义pixmap。 QMessageBox::Icon icon(

【强化学习的数学原理】第02课-贝尔曼公式-笔记

学习资料:bilibili 西湖大学赵世钰老师的【强化学习的数学原理】课程。链接:强化学习的数学原理 西湖大学 赵世钰 文章目录 一、为什么return重要?如何计算return?二、state value的定义三、Bellman公式的详细推导四、公式向量形式…

【数据结构实战篇】用C语言实现你的私有队列

🏝️专栏:【数据结构实战篇】 🌅主页:f狐o狸x 在前面的文章中我们用C语言实现了栈的数据结构,本期内容我们将实现队列的数据结构 一、队列的概念 队列:只允许在一端进行插入数据操作,在另一端…

实战项目负载均衡式在线 OJ

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:能自己实现负载均衡式在线 OJ。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自&#xff1…

银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法

银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法 1、支持环境2、详细操作说明步骤1:用root账户登录电脑步骤2:导航到kylin-wm-chooser目录步骤3:编辑default.conf文件步骤4:重启电脑 3、结语 &#x1f49…

数据结构--AVL树(平衡二叉树)

✅博客主页:爆打维c-CSDN博客​​​​​​ 🐾 🔹分享c、c知识及代码 🐾 🔹Gitee代码仓库 五彩斑斓黑1 (colorful-black-1) - Gitee.com 一、AVL树是什么?(含义、性质) 1.AVL树的概念 AVL树是最…

【Unity How】如何让物体跟随平台移动或旋转?

先看下最终要实现的效果: 当查找这个问题的资料时,发现多数的方案都是将物体设置为平台的子对象。 但是如果平台是非均匀缩放时,物体在移动或旋转时就会发生变形。 参考:Unity中父对象是非均匀缩放时出现倾斜或剪切现象 那有没有…

C语言函数递归经典题型——汉诺塔问题

一.汉诺塔问题介绍 Hanoi(汉诺)塔问题。古代有一个梵塔,塔内有3个座A、B、C,开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从A座移…

Unity中动态生成贴图并保存成png图片实现

实现原理&#xff1a; 要生成长x宽y的贴图&#xff0c;就是生成x*y个像素填充到贴图中&#xff0c;如下图&#xff1a; 如果要改变局部颜色&#xff0c;就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理&#xff0c; 或者要想做圆形就是计算距某个点&#xff08;x1,y1&…

vue3封装Element Plus table表格组件

支持绝大部分Element Plus原有设置属性&#xff0c;支持分页&#xff0c;支持动态适配高度 效果展示 组件代码&#xff1a; <template><div class"table-wrap" ref"tableWrap"><el-tableclass"w100 h100":data"tableInfo.…

ElasticSearch学习篇18_《检索技术核心20讲》LevelDB设计思想

目录 一些常见的设计思想以及基于LSM树的LevelDB是如何利用这些设计思想优化存储、检索效率的。 几种常见的设计思想 索引和数据分离减少磁盘IO读写分离分层思想 LevelDB的设计思想 读写分离设计分层设计与延迟合并LRU缓存加速检索 几种常见设计思想 索引与数据分离 索引…

路由器中继与桥接

一 . 背景 现在的路由器大多数已经开始支持多种网络连接模式&#xff0c;以下将以TP-Link迷你无线路由器为例进行展开介绍。在TP-Link迷你无线路由器上一般有AP&#xff08;接入点&#xff09;模式&#xff0c;Router&#xff08;无线路由&#xff09;模式&#xff0c;Repeate…

Bitcoin---P2SH;P2SH举例;P2SH的局限性

文章目录 1. 摘要2. P2SH举例3. P2SH局限性 1. 摘要 Pay-to-Script-Hash (P2SH) 交易输出的开发是为了简化更复杂和功能性脚本的使用&#xff0c;就像需要提供相应签名才能解锁的支付脚本&#xff08;即 P2PKH 脚本&#xff09;一样简单。为了轻松使用此类兑换脚本&#xff0c…

鸿蒙NEXT开发案例:文字转拼音

【引言】 在鸿蒙NEXT开发中&#xff0c;文字转拼音是一个常见的需求&#xff0c;本文将介绍如何利用鸿蒙系统和pinyin-pro库实现文字转拼音的功能。 【环境准备】 • 操作系统&#xff1a;Windows 10 • 开发工具&#xff1a;DevEco Studio NEXT Beta1 Build Version: 5.0.…

ffmpeg视频滤镜:提取缩略图-framestep

滤镜描述 官网地址 > FFmpeg Filters Documentation 这个滤镜会间隔N帧抽取一帧图片&#xff0c;因此这个可以用于设置视频的缩略图。总体上这个滤镜比较简单。 滤镜使用 滤镜参数 framestep AVOptions:step <int> ..FV....... set frame st…

eclipse-git项目提示NO-HEAD

1、出现该问题的过程 本人在用eclipse拉取git代码&#xff0c;刚拉取完&#xff0c;可能还没来得及跟本地的分支合并&#xff0c;电脑就卡动了。无奈只能重启电脑&#xff0c;打开eclipse&#xff0c;maven项目后面就出现了xxx NO-HEAD的提示。 2、问题解决 根据错误提示&am…

力扣hot100-->排序

排序 1. 56. 合并区间 中等 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输…

鱼眼相机模型-MEI

参考文献&#xff1a; Single View Point Omnidirectional Camera Calibration from Planar Grids 1. 相机模型如下&#xff1a; // 相机坐标系下的点投影到畸变图像// 输入&#xff1a;相机坐标系点坐标cam 输出&#xff1a; 畸变图像素点坐标disPtvoid FisheyeCamAdapter::…

Reactor 模式的理论与实践

1. 引言 1.1 什么是 Reactor 模式&#xff1f; Reactor 模式是一种用于处理高性能 I/O 的设计模式&#xff0c;专注于通过非阻塞 I/O 和事件驱动机制实现高并发性能。它的核心思想是将 I/O 操作的事件分离出来&#xff0c;通过事件分发器&#xff08;Reactor&#xff09;将事…