【Rust进阶】通过测试驱动开发学习:03_单链表的插入

微软开源 windows-drivers-rs,用 Rust 开发 Windows 驱动程序 Microsoft Azure 首席技术官兼著名 Windows 软件开发人员 Mark Russinovich 在社交平台上宣布,启动了一个名为 windows-drivers-rs 的新开源项目。 阅读详情

在具体代码实现之前,先将上一章节我们接触到的一些Rust语法做一些简答的说明。

Option

Option是Rust标准库中定义的一种枚举,它有两个变体:Some和None.

Some包装了一个具体的值,而None表示失败或缺少值。

在很多编程语言中会有空值(Null)这一个概念,但在Rust中并没有,因为容易因空指针引起一些不安全的问题。

当一个值可能有也可能没有的时候,在Rust中就需要你明确的处理这两种情况。

Box

在Rust中,Box是一种智能指针类型,用于在堆上分配内存并存储数据。

  • Box类型本身是一个智能指针,它存储在栈上。
  • Box里面指向的数据是存储在堆上。
let a = Box::new(1);

box

根据上述代码,可以看出来a只是一个存储在栈上的智能指针,如果我们想用里面的值,我们需要进行解引用Deref操作。

链表操作

单链表的使用都是默认带头结点的,你可以自己在练习的时候思考一下如果是不带头结点的链表如何实现这些基本操作,在不同的使用场景各有优劣,但对你来说更能加深对数据结构和Rust语法的理解。

1. 插入

1.1 头插法建立单链表
编写测试
  1. 新建链表
// linked_list/src/lib.rs

// Unit tests
#[cfg(test)]
mod test {
    use super::*;
  
  	// ......................................
		#[test]
  	fn test_list_insert_in_head() {
      let mut list: LinkedList<i32> = LinkedList::new(0);
      assert_eq!(list, LinkedList { head: Some(Box::new(LinkedNode { data: 0, next: None })) });
  }
}
运行测试

编译错误 ❌

image-20240312102733656

分析
  1. 我们的LinkedList结构体没有实现PartialEq这个trait,从而两个实例不能够进行相等性的比较。
解决方法
  1. 给LinkedList和LinkedNode添加上PartialEq这个trait。
// linked_list/src/lib.rs

// ......................................

#[derive(Debug,PartialEq)]
pub struct LinkedNode<T> {
    data: T,
    next: Option<Box<LinkedNode<T>>>,
}

#[derive(Debug,PartialEq)]
pub struct LinkedList<T> {
    head: Option<Box<LinkedNode<T>>>,
}

运行测试 ✅
编写测试
  1. 链表插入
// linked_list/src/lib.rs

// Unit tests
#[cfg(test)]
mod test {
    use super::*;
  
  	// ......................................
		#[test]
    fn test_list_insert_in_head() {
        let mut list: LinkedList<i32> = LinkedList::new(0);
        list.insert_head(1);
        assert_eq!(list, LinkedList { head: Some(Box::new(LinkedNode { data: 0, next: Some(Box::new(LinkedNode { data: 1, next: None })) })) });
    }
} 
运行测试

编译错误 ❌

image-20240312103808564

分析
  1. 我们现在还没有定义这个插入方法
解决方法
  1. 先创建该插入方法,使其能够编译通过。

    我们不要想着一步到位,想着让其一下子就跑通,我们需要重复测试开发这几个环节,将我们的代码一点点完善起来。

// linked_list/src/lib.rs

impl<T> LinkedList<T> {

  // ......................................
  // insert node in this linked list head
    pub fn insert_head(&mut self, value: T) {
    
    }
}
运行测试

测试失败 ❌

image-20240312111939956

分析

目前我们已经修复了编译错误,代码可以进行测试了,但是测试失败,左右不相等,不符合我们的预期。

  1. 我们定义的头插法,里面还没有写具体的操作代码,将代码进行完善,使其测试通过。
解决方法
  1. 完善insert_head方法,注意链表是带头结点。
  2. 目前先不管头结点里面存放数据问题,先让插入能够在头结点之后正常插入。
// linked_list/src/lib.rs

impl<T> LinkedList<T> {
// ------------------------------------------
// insert node in this linked list head
    pub fn insert_head(&mut self, value: T) {
        let new_node = LinkedNode {
            data: value,
            next: self.head.as_mut().unwrap().next.take(),
        };

        self.head.as_mut().unwrap().next = Some(Box::new(new_node));
    }
}
代码说明
  1. 创建了一个新的链表结点,将头结点所指的next赋给新结点的next。
  2. 此时头结点的next指向None。
  3. 将头结点的next重新指向新结点。

list_insert_head

  1. as_mut

    在Rust中,可变引用允许对数据进行可变访问和修改。可变引用是一种指向数据的引用,允许在引用的生命周期内对数据进行更改。这种机制使得Rust能够在编译时确保内存安全,避免数据竞争和未定义行为。

    使用可变引用的主要作用包括:

    1. 修改数据:通过可变引用,可以在不转移所有权的情况下修改数据。这使得可以在程序中安全地进行数据的更改和更新。
    2. 避免数据竞争:Rust的借用规则确保了在同一时间只能有一个可变引用,从而避免了数据竞争的发生。这种限制使得在编译时就能够避免多线程并发访问数据时可能出现的问题。
    3. 内存安全:可变引用的使用受到Rust的借用规则的限制,确保了在编译时就能够预防空指针、野指针等内存安全问题。

    Option 类型的 as_mut 方法允许您将 Option 转换为包含可变引用的 Option。这意味着您可以在 Option 包含的值上进行可变操作,而不需要将值从 Option 中取出。

  2. take

    Option 类型的 take 方法允许您从 Option 中取出值,并将 Option 设置为 None。

​

运行测试 ✅
// linked_list/src/lib.rs

#[cfg(test)]
mod test {
  
// ---------------------------------------------
#[test]
    fn test_list_insert_in_head() {
        let mut list: LinkedList<i32> = LinkedList::new(0);
        list.insert_head(1);
        assert_eq!(
            list,
            LinkedList {
                head: Some(Box::new(LinkedNode {
                    data: 0,
                    next: Some(Box::new(LinkedNode {
                        data: 1,
                        next: None
                    }))
                }))
            }
        );
        list.insert_head(2);
        assert_eq!(
            list,
            LinkedList {
                head: Some(Box::new(LinkedNode {
                    data: 0,
                    next: Some(Box::new(LinkedNode {
                        data: 2,
                        next: Some(Box::new(LinkedNode {
                            data: 1,
                            next: None
                        }))
                    }))
                }))
            }
        );
        list.insert_head(3);
        assert_eq!(
            list,
            LinkedList {
                head: Some(Box::new(LinkedNode {
                    data: 0,
                    next: Some(Box::new(LinkedNode {
                        data: 3,
                        next: Some(Box::new(LinkedNode {
                            data: 2,
                            next: Some(Box::new(LinkedNode {
                                data: 1,
                                next: None
                            }))
                        }))
                    }))
                }))
            }
        );
    }
}

我们可以多添加几个测试案例,尤其一些特殊情况下的处理。

我在代码中还实现了Display方法,可以使用打印,来查看目前我们链表的结构,关于该方法后续再介绍。

这是带头结点的头插法,你快动手试试如何使用不带头结点的头插法。

image-20240312122313556

版本管理

当我们测试通过后,我们使用git将我们的代码添加到本地仓库中。

1.2 尾插法建立单链表

完成了头插法,我们接下来进行尾插法的代码编写,但是步骤有所区别,因为我们这里并不知道表尾在哪里。所以我们需要遍历一下链表,找到表尾,然后在其后面插入数据。

先不考虑这么多,我们还是采用TDD的开发方式,来进行一步步开发。

list_insert_tail

编写测试
// linked_list/src/lib.rs

#[cfg(test)]
mod test {
  // --------------------
  
  #[test]
    fn test_list_insert_in_tail() {
        let mut list = LinkedList::new(0);
        list.insert_tail(1);
        list.insert_tail(2);
        list.insert_tail(3);
        assert_eq!(
            list,
            LinkedList {
                head: Some(Box::new(LinkedNode {
                    data: 0,
                    next: Some(Box::new(LinkedNode {
                        data: 1,
                        next: Some(Box::new(LinkedNode {
                            data: 2,
                            next: Some(Box::new(LinkedNode {
                                data: 3,
                                next: None
                            }))
                        }))
                    }))
                }))
            }
        );
    }
}
运行测试

编译错误 ❌

分析
  1. 我们只编写了测试还没有编写该方法。
解决方法
  1. 编写insert_tail方法

这次我们将方法写完后再运行测试,你也可以根据头插法,先修复代码使其能够编译运行,测试不通过再通过修改添加代码功能来解决。

代码说明
  1. 从链表的第一个结点开始,遍历,直到找到最后一个结点**(指向None)**。
  2. 找到最后一个结点后,创建一个新的结点,并插入在已经找到的最后一个结点的后面。
// linked_list/src/lib.rs

impl<T> LinkedList<T> {

    // ------------------------------------------
  	// insert node in this linked list tail
    pub fn insert_tail(&mut self, value: T) {
        let mut current_node = &mut self.head;
        while let Some(node) = current_node {
            if node.next.is_none() {
                let new_node = LinkedNode {
                    data: value,
                    next: None,
                };
                node.next = Some(Box::new(new_node));
                return;
            }
            current_node = &mut node.next;
        }
    }
}
运行测试 ✅

image-20240312125727740

同时我们也可以看到,Cargo 默认会以多线程的方式运行多个测试。这意味着多个测试将会并行执行,以加快测试的运行速度并更快地提供反馈。

可以使用 --test-threads 标志并将线程数设置为 1。这样可以确保测试按顺序执行,避免测试之间相互干扰。

image-20240312125958846

版本管理

当我们测试通过后,我们使用git将我们的代码更新提交到到本地仓库中。

下一章讲介绍链表的查找和在某个位置插入操作。

2025 AI工程师核心能力:提示工程、可观测性与AI原生架构实战 AI工程已从模型调参迈入系统化落地阶段。提示工程本质是人机协作协议设计,需支撑结构化输出与业务系统无缝集成;AI系统可观测性不是日志监控,而是覆盖数据、模型、服务、业务四维的诊脉式归因能力;AI原生架构强调任务驱动的微服务网格与弹性边界划分,拒绝大模型中心化套壳。这些能力共同构成AI产品化落地的技术基座——决定算法能否真正嵌入产线排程、医保审核、政务工单等高敏场景。本文基于8类行业真实项目(制造业缺陷识别、零售销量归因、智能风控等),拆解可验证、可测量、可审计的工程实践路径。 阅读详情

相关推荐

嵌入式面试核心:C语言、RTOS与通信协议高频考点解析

在计算机体系结构中,嵌入式系统作为连接硬件与软件的桥梁,其开发要求工程师深入理解底层原理与资源受限环境下的工程实践。从C语言的内存模型与指针运算,到操作系统的任务调度与同步机制,这些基础概念构成了嵌入式开发的核心知识体系。其技术价值在于实现高可靠性、实时性与低功耗的系统设计,广泛应用于物联网设备、工业控制、汽车电子等领域。本文聚焦嵌入式岗位面试中的经典题目,深入剖析指针、volatile关键字、RTOS任务调度及I2C/SPI通信协议等高频考点,帮助工程师巩固基本功,掌握面试官考察的底层逻辑与工程思维。

weixin_34189116的博客 327

11. Linux驱动 - Rust编写Linux驱动

Linux 中设备通常被分为三类,每个驱动模块通常实现为这三类中的其中一种: 字符设备。通常是指可以当作一个字节流来存取的设备(比如文件)。 块设备。通常是可以驻有文件系统的设备(比如磁盘),和字符设备类似,但块设备有一个请求缓冲区,因此它们可以选择响应请求的最佳顺序。 网络设备。通常是指能与其他主机交换数据的设备。 我们以编写一个简单的字符设备驱动为例,展示如何用 Rust 来编写内核驱动。 R4L 开发环境准备 为了方便,我们把 Rust for Linux 简称为 R4L。 首先,下载 Rust

笨笨D幸福 - 后花园 4549

【信息科学与工程学】计算机科学与自动化——第三百零五篇 计算机系统中的各类运算操作01

编号类型领域运算操作运算类型算法算法的详细设计及数学分析参数列表及参数的数值设计应用场景 (100+条)集合运算​1集合运算关系代数并集 (Union)集合运算归并排序去重合并两个集合,去除重复元素。时间复杂度 O(n+m),n,m为两集合大小。输入:集合A, B。输出:A∪B。数据集成、多表结果合并、去重后的全量数据提取。2集合运算关系代数交集 (Intersection)集合运算哈希交集找出同时属于两个集合的元素。平均时间复杂度 O(min(n,m)),最坏 O(n*m)。输入:集合A, B。输出:A∩

weixin_49199313的博客 1388

【一起学Rust · 项目实战】命令行IO项目minigrep——测试驱动开发完善功能

经过前面三节的学习,我们的小工具minigrep已经实现了读取指定文件内容,并且为了后期开发和测试的方便,重构了整个项目,使错误处理规整化,模块规范化。本次我们将采用测试驱动开发(以后简称TDD)的模式进行开发,为程序编写几个程序测试用例,测试程序搜索查询字符串并返回匹配的行示例的功能,这些功能会在后面开发过程中用到。测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。.........

专注Rust编程与技术分享,涵盖C++、Python等开发实战,新手友好,专注实战,助力编程成长。 8万+

后端开发:Rust打造高效的事件驱动系统

在当今的后端开发领域,高效处理大量并发请求是一个关键挑战。事件驱动系统因其能够高效地处理异步事件,成为了应对这一挑战的重要解决方案。本文章的目的是详细介绍如何使用Rust语言来打造高效的事件驱动系统。范围涵盖了事件驱动系统的基本概念、核心算法原理、实际项目开发以及相关的工具和资源推荐。

架构师的AI之路,分享AI应用开发架构的学习与实践。 1090

一个工具包,可以更快地创建更好的Rust设备驱动程序-Rust开发

用于创建更好的Rust设备驱动程序的工具包,更快的设备驱动程序工具包#![no_std]一种用于编写更好的设备驱动程序的工具包,可以更快地在Apache License 2.0版(LICENSE-APACHE或http://www.apache)下获得许可。 org / licenses / LICENSE-2.0)MIT许可证(LICENSE-MIT或http://opensource.org/licenses/MIT),由您选择。 贡献除非您明确声明,否则,您有意提交以包含在Apache-2.0许可证中的内容由您包括在作品中的任何贡献均应如上所述获得双重许可,并且

Rust之构建命令行程序(四):用TDD(测试-驱动-开发)模式来开发库的功能

Rust之构建命令行程序(四):用TDD(测试-驱动-开发)模式来开发库的功能

wing的专栏 1549

GPIB通讯的代码怎么写

GPIB(General Purpose Interface Bus)是一种用于连接计算机和测试设备的接口标准。 在写 GPIB 通讯的代码时,首先需要在计算机上安装 GPIB 驱动程序。然后,使用相应的编程语言和 GPIB 库函数来操作 GPIB 设备。 下面是一个使用 Python 语言和 pyvisa 库来实现 GPIB 通讯的示例代码: import visa# 创建 Visa 资源管理器...

weixin_35752645的博客 1545

【Rust进阶】通过测试驱动开发学习:01_介绍

在这个系列的开篇,我们将探索如何通过测试驱动开发(TDD)来学习Rust编程语言。TDD是一种软件开发方法,它鼓励先编写单元测试,然后编写满足测试的代码,最后重构代码以优化设计。本节介绍了TDD的基本概念,以及如何在Rust中实现它。我们将从创建一个注定失败的测试开始,然后编写通过该测试的代码,并逐步构建出功能完整的Rust应用程序。这种方法不仅能帮助我们更深入地理解Rust的特性,还能确保我们的代码质量和可维护性。随着我们的进展,我们将不断回顾和应用Rust的高级特性,使我们的代码更加健壮和高效。

编程不止 1180

Claude Code VSCode集成开发指南:AI编程助手完整配置

Claude Code与Visual Studio Code的深度集成为开发者提供了强大的AI编程支持。本文详细介绍Claude Code VSCode扩展的安装配置、功能特性和实际应用方法。通过完整的配置流程和代码示例,帮助开发者充分利用Claude AI的智能编程能力。文章涵盖从环境搭建到高级功能应用的完整指南,包括代码自动补全、智能重构、实时代码分析等核心功能的使用技巧,以及与现有开发工作流的整合方案。

2501_93058131的博客 5979

embedding计算过程

文章目录embedding计算过程(错了跟我讲,我会改)参考示例个人理解过程图示总结(基于pytorch) embedding计算过程(错了跟我讲,我会改) 参考示例 https://www.jianshu.com/p/63e7acc5e890 个人理解过程图示 总结(基于pytorch) 总的来说,就是将独热向量的长度(对应嵌入层的num_embeddings)转变为嵌入层的emdedding_size(而独热向量的维数就是你的数据中一共产生了多少个不一样的词,至少是这么多)。 数据的变化,将二维

纸上得来终觉浅,绝知此事要躬行! 1631

怎样高效掌握数据结构与算法:50个必知必会代码实现全面指南

数据结构和算法是程序员编程能力的核心基础,也是面试和职业发展中的关键技能。Algo项目提供了50个数据结构和算法的代码实现,涵盖从基础到高级的完整知识体系,帮助开发者系统性地掌握这一重要领域。 ## 🚀 项目核心价值与学习路径 这个算法学习项目最大的特色是**多语言实现**,同一个算法在C/C++、Java、Python、Go、JavaScript、Rust、Swift、PHP、Scala、

gitblog_00383的博客 1101

完整的 Python 数据分析案例:新能源汽车续航里程预测

随着新能源汽车的普及,续航里程成为消费者关注的重要指标。准确预测新能源汽车的续航里程,有助于车企优化电池管理系统、提升车辆性能,也能帮助消费者合理规划出行。本案例将基于新能源汽车的各项参数,如电池容量、行驶速度、环境温度等,构建续航里程预测模型。通过以上改进,可以提高数据处理的准确性、模型的性能和可视化的效果。

daqsdfas的博客 1587

Isaac Lab 仿真对比指南:用 PXD2/OVD 逐帧校验 Isaac Gym 迁移后物理一致性

当把一套强化学习或控制仿真从 Isaac Gym 迁移到 Isaac Lab 时,最常见的疑虑不是"代码能不能跑",而是"两个环境的物理行为是否等价"。由于默认值解释、导入器对物体层级的处理、以及数值缩放方式都可能不同,肉眼或看训练曲线都无法给出确定答案。本篇指南给出一套可落地的比对方法:利用 PhysX 在两个平台上同源的引擎特性,分别录制 **PXD2**(Isaac Gym)与 **OVD*

gitblog_01168的博客 312

8.26华为OD机试真题 新系统 - 字符串回文判 (Java/Py/C/C++/Js/Go)

8.26华为OD机试真题 新系统 - 字符串回文判 (Java/Py/C/C++/Js/Go)

算法大师! 1230

UG\NX二次开发 获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态

获取对象的层、颜色、隐藏状态、线宽、线型、高亮显示状态。

王牌飞行员_里海的博客 1980

UIUC CS225数据结构课程:从C++底层实现到工程能力的深度构建

数据结构是计算机科学的核心基础,它研究数据在内存中的组织、存储和操作方式,直接影响程序的效率和可维护性。其原理在于通过特定的逻辑结构和物理结构,如线性表、树、图等,来高效地支持数据的增删改查。掌握数据结构的技术价值在于,它不仅是算法运行的载体,更是培养系统思维、理解复杂系统设计的关键。在实际应用场景中,从数据库索引、操作系统调度到网络路由,都深度依赖高效的数据结构。本文以UIUC CS225课程为例,探讨如何通过C++手动实现**内存管理**和**指针操作**等底层细节,跨越从理论认知到编写工业级健壮代码的

weixin_30608503的博客 435

LPDDR6 tdbR2dbR_L cross row技术探讨

LPDDR6 tdbR2dbR_L cross row技术探讨

zilan23的博客 47

【Rust类型驱动开发 Type Driven Development】

type-diven development,即将开发者需要的逻辑约束条件编码到类型系统中,举个例子,一般业务逻辑下开发者通常需要检查输入的正确性,一般情况下开发者的思维惯性会在调用function的内部做一些逻辑判断,比如字符串长度是否符合条件,格式是否符合如人名,邮箱地址等等。类型驱动开发是将此类检查放在形成某一种类型的时候完成,即如果逻辑不通则不会形成需要的类型,同样的,类型驱动开发也具备一定的封装性,保证开发者不会因为误用而破坏流程的安全性和产生一些垃圾数据。

m0_37719524的博客 934

在 Zynq 7010 上运行 VxWorks 7.0 的详细流程【持续更新】

本文介绍了在Zynq 7010开发板上运行VxWorks 7.0的完整流程。主要包括:1)使用Vivado创建硬件设计,配置Zynq模块并生成比特流文件;2)通过Workbench 4创建VxWorks工程,配置启动参数并生成镜像;3)下载运行步骤。此外还讲解了使用Workbench 4开发VSB和VIP工程的方法,包括工程创建、配置和调试流程。文中提供了关键操作截图和注意事项,为开发者提供了完整的Zynq 7010平台VxWorks开发解决方案。

weixin_45397344的博客 1223

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

# 发散创新:用Rust编写高性能驱动程序的实战指南在现代操作系统中,**驱动程序是

在现代操作系统中,。传统上,C语言因其接近硬件的能力长期主导这一领域,但近年来,Rust凭借其内存安全性和并发模型优势逐渐崭露头角。本文将带你从零开始构建一个基于,并通过实际代码演示如何实现注册、读写、卸载等核心功能。

hai1234yang的博客 58

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【Rust自学】12.6. 使用TDD(测试驱动开发)开发库功能

第12章要做一个实例的项目——一个命令行程序。这个程序是一个`grep`(Global Regular Expression Print),是一个全局正则搜索和输出的工具。本文负责完善搜索函数,使用TDD(测试驱动开发)理念来开发功能。这篇文章有助于你学习实战中开发功能的步骤。

A Rookie in San Domenico School 1403

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【Rust进阶】通过测试驱动开发学习:02_项目搭建

搭建第一个项目:一个简单链表的实现

编程不止 1282

Rust 与嵌入式开发:从硬件驱动到完整系统

引言在嵌入式开发领域,传统上 C 和 C++ 占据着主导地位。然而,随着技术的不断演进,Rust 作为一门新兴的编程语言,正逐渐崭露头角,为嵌入式开发带来了全新的思路与解决方案。Rust 语言凭借其独特的设计理念,在安全性、性能以及开发效率等方面展现出了显著的优势,尤其适用于对稳定性和可靠性要求极高的嵌入式系统开发场景。本文将深入探讨 Rust 在嵌入式开发中的应用,从硬件驱动的编写开始,逐步构建完整的嵌入式系统,展示 Rust 如何为嵌入式开发带来变革。

数字魔方操控师的博客 1447

Rust 工程实践:从模块化到测试驱动开发

Rust 的成功不仅来自语言层面,更来自它的工程文化模块化让系统结构可维护;测试驱动保证可靠性;工具链提升开发效率;持续集成确保稳定交付。这种体系化的设计让 Rust 不仅适合写底层库或嵌入式程序,也能支撑大型分布式系统、Web 服务与企业级平台。掌握这些工程化实践,你就不只是“会写 Rust”,而是能用 Rust 构建可持续演进的软件系统。

m0_74256065的博客 808

揭秘Rust在MCU上的应用:如何用零成本抽象实现安全驱动开发

掌握Rust嵌入式开发安全新范式,揭秘如何在MCU上通过零成本抽象构建高效驱动。适用于ARM Cortex-M等微控制器,兼顾内存安全与性能,避免运行时开销。实现高可靠底层编程,值得收藏。

AlgoChat的博客 431
上一篇: 【Rust进阶】通过测试驱动开发学习:02_项目搭建
下一篇: 【Rust实战】Axum + Nextjs 前后端全栈开发01:介绍
SunsJay
博客等级 码龄6年 95粉丝 7原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值