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

文章目录

  • 深入理解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模式可以提升代码质量和可维护性,尤其是在处理复杂类型和多种不同数据单元的场景中。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS Pro】实现一下完美的坐标点标注

在CAD里利用湘源可以很快点出一个完美的坐标点标注。 但是在ArcGIS Pro中要实现这个效果却并不容易。 虽然有点标题党,这里就尽量在ArcGIS Pro中实现一下。 01 标注实现方法 首先是准备工作,准备一个点要素图层,包含xy坐标字段。 在地图框…

【ArcGIS Pro实操第10期】统计某个shp文件中不同区域内的站点数

统计某个shp文件中不同区域内的站点数 方法 1:使用“空间连接 (Spatial Join)”工具方法 2:使用“点计数 (Point Count)”工具方法 3:通过“选择 (Select by Location)”统计方法 4:通过“Python 脚本 (ArcPy)”实现参考 在 ArcGI…

学习threejs,使用设置lightMap光照贴图创建阴影效果

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.MeshLambertMaterial…

Cocos编辑器

1、下载 下载地址:https://www.cocos.com/creator-download 2、编辑器界面介绍 官方链接:https://docs.cocos.com/creator/3.8/manual/zh/editor/ 3、项目结构 官方链接:https://docs.cocos.com/creator/3.8/manual/zh/getting-started/…

C++11特性(详解)

目录 1.C11简介 2.列表初始化 3.声明 1.auto 2.decltype 3.nullptr 4.范围for循环 5.智能指针 6.STL的一些变化 7.右值引用和移动语义 1.左值引用和右值引用 2.左值引用和右值引用的比较 3.右值引用的使用场景和意义 4.右值引用引用左值及其一些更深入的使用场景分…

Notepad++ 替换所有数字给数字加单引号

前言 今天遇到这样一个场景: 要去更新某张表里 code1,2,3,4,5,6 的数据,把它的 name 设置为 ‘张三’ 但是 code在数据库里面的字段类型是 vachar(64),它自身携带索引 原本可以这样写 SQL: update tableA set namezhangsan where code in …

Django 路由层

1. 路由基础概念 URLconf (URL 配置):Django 的路由系统是基于 urls.py 文件定义的。路径匹配:通过模式匹配 URL,并将请求传递给对应的视图处理函数。命名路由:每个路由可以定义一个名称,用于反向解析。 2. 基本路由配…

工作中可以用到的前端小知识(不定时更新)

1、split 结合 filter(Boolean)使用,可以过滤空字符 2、分割 Unicode 字符 用 Array.from() 实现 const text "👍😊👨‍👩‍👦"; const result Array.from(text); console.log(result); // 输…

第R4周:LSTM-火灾温度预测(TensorFlow版)

>- **🍨 本文为[🔗365天深度学习训练营]中的学习记录博客** >- **🍖 原作者:[K同学啊]** 往期文章可查阅: 深度学习总结 任务说明:数据集中提供了火灾温度(Tem1)、一氧化碳浓度…

CTF-Hub SQL 报错注入(纯手动注入)

​ 当输入1时,发现只有查询正确,基本上可以判断出没有回显 开始注入(工具hackerBar) 题目是报错注入,方向就比较明显,大致说一下用到的函数和原理。 常见报错注入函数: 通过 floor() 报错注入通过 extractValue() …

创建HTTPS网站

每天,我们都会听到网络上发生身份盗窃和数据侵权的案例,这导致用户对自己访问的网站更加怀疑。他们开始更加了解自己将个人信息放在哪里以及信任哪些类型的网站。了解如何使网站使用HTTPS变得比以往任何时候都更加重要。 解读缩略词:HTTP与HT…

计算(a+b)/c的值

计算(ab)/c的值 C语言代码C语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 给定3个整数a、b、c,计算表达式(ab)/c的值,/是整除运算。 输入 输入仅一行&…

Flink Sink的使用

经过一系列Transformation转换操作后,最后一定要调用Sink操作,才会形成一个完整的DataFlow拓扑。只有调用了Sink操作,才会产生最终的计算结果,这些数据可以写入到的文件、输出到指定的网络端口、消息中间件、外部的文件系统或者是…

Java【多线程】(1)进程与线程

目录 1.前言 2.正文 2.1什么是进程 2.2PCB(进程控制块) 2.2.1进程id 2.2.2内存指针 2.2.3文件描述符表 2.2.4进程状态 2.2.4.1就绪状态 2.2.4.2阻塞状态 2.2.5进程优先级 2.2.6进程上下文 2.2.7进程的记账信息 2.3CPU操作进程的方法 2.4什…

一个专为云原生环境设计的高性能分布式文件系统

大家好,今天给大家分享一款开源创新的分布式 POSIX 文件系统JuiceFS,旨在解决海量云存储与各类应用平台(如大数据、机器学习、人工智能等)之间高效对接的问题。 项目介绍 JuiceFS 是一款面向云原生设计的高性能分布式文件系统&am…

Jmeter中的断言

7)断言 1--响应断言 功能特点 数据验证:验证响应数据是否包含或不包含特定的字符串、模式或值。多种匹配类型:支持多种匹配类型,如文本、正则表达式、文档等。灵活配置:可以设置多个断言条件,满足复杂的测…

游戏引擎学习第23天

实时代码编辑功能的回顾 当前实现的实时代码编辑功能已经取得了显著的成功,表现出强大的性能和即时反馈能力。该功能允许开发者在修改代码后几乎立即看到变化在运行中的程序中体现出来,极大提升了开发效率。尽管目前的演示内容较为简单,呈现…

排序算法之冒泡排序篇

冒泡排序的思想: 是一个把元素从小到大排的一个算法思想 相邻的两个元素两两比较,大的那一个元素向后移,小的那个元素向前移 核心逻辑: 比较所有相邻的两个项,如果第一个比第二个大,就交换它们 从头开始…

Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚

我的个人主页 我的专栏:Java-数据结构,希望能帮助到大家!!!点赞❤ 收藏❤ 前言:在 Java编程的广袤世界里,数据结构犹如精巧的建筑蓝图,决定着程序在数据处理与存储时的效率、灵活性以…

【笔记】自动驾驶预测与决策规划_Part8_数据驱动的规划方法

文章目录 0. 前言1.生成模型1.1 Diffusion-ES1. Diffusion-ES算法介绍2. Diffusion-ES算法具体流程Diffusion Model 是什么?Diffusion-ES: Evolutionary StrategiesDiffusion-ES MethodDiffusion-ES Mapping Language instructions to reward functions with LLM pr…