Rust学习笔记007:Trait --- Rust的“接口”

123、Rust 编程与 Swagger API 设计:打造高效、易维护的接口 本文介绍了Rust编程语言中遵循RESTful原则和集成Swagger的重要性,以及如何使用Swagger UI展示API文档。我们探讨了RESTful原则的核心概念、应用场景和实用技巧,并学会了如何使用Swagger进行API文档编写和维护。最后,我们通过一个简单的Rust示例了解了如何在Rust中集成Swagger,以实现API的文档化和可视化。 阅读详情
AI摘要

本文深入讲解Rust语言中的特质(Trait)概念,包括定义、实现、泛型使用及trait bound形式等,帮助读者理解如何利用特质提升代码复用性和灵活性。

Trait

  • 在Rust中,Trait(特质)是一种定义方法集合的机制,类似于其他编程语言中的接口(java)或抽象类(c++的虚函数)。

定义Trait

trait MyTrait { //关键字trait(线条、特征、勾勒)
    // 定义Trait的方法
    fn my_method(&self);//只有方法签名,没有具体实现,实现该trait的类型必须提供具体实现

    // 可选:可以在这里定义其他方法
    fn my_method_1(&self)-> String {
        String::from("也可以提供默认实现")
    };
}

实现Trait

struct MyStruct;

//实现trait用impl这个关键字,格式为impl trait_name for struct_name{}。impl另一个主要的用途是实现struct的“类成员方法”,格式为impl struct_name{}
impl MyTrait for MyStruct {
    fn my_method(&self) {
        println!("This is the implementation for my_method in MyStruct");
    }
}

孤儿规则

  • 可在某个类型上实现trait:

    • 类型或者trait在当前作用域中定义的
  • 无法为外部类型来实现外部的trait:

    • 这个限制是程序属性的一部分(也就是一致性)。
    • 更具体的说是孤儿规则:之所以这样命名是因为父类型不存在。
    • 此规则确保其他人的代码不能破坏您的diamond,反之亦然。
    • 如果没有这个规则,两个crate可以为同一个理性实现同一个trait,Rust就不知道该使用哪个实现了。
    • 如果允许任意 crate 对任意类型实现任意 trait,可能会导致多个 crate 中的相同类型实现相同的 trait,这会引起冲突和不可预期的行为。

引入与使用Trait

简单示例:

// 定义一个 Trait
trait Animal {
    fn make_sound(&self);
}

// 实现 Trait for struct Dog
struct Dog;

impl Animal for Dog {
    fn make_sound(&self) {
        println!("Woof!");
    }
}

// 使用 Trait 对象
fn print_sound(a: &dyn Animal) {
    a.make_sound();
}

fn main() {
    let dog = Dog;
    // 两种调用方法
    dog.make_sound(); // 输出: Woof!
    print_sound(&dog); // 输出: Woof!
}

将trait打包到库中

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Trait作为参数

在这里插入图片描述

使用多个Trait

// 定义两个trait,一个“总结”,一个“展示”
trait Summary {
    fn summarize(&self) -> String;
}
trait Display {
    fn display(&self);
}



// 定义结构体 CCTV
struct CCTV {
    author: String,   content: String,
}
// 为CCTV实现总结功能
impl Summary for CCTV {
    fn summarize(&self) -> String {
        format!("{}, by {}", self.content, self.author)
    }
}
// 为CCTV实现展示功能
impl Display for CCTV {
    fn display(&self) {
        println!("Author: {}", self.author);
        println!("Content: {}", self.content);
    }
}



// 定义一个函数,接受实现了 Summary 和 Display traits 的对象作为参数
pub fn notify(item: &(impl Summary + Display)) {
    println!("Breaking news!");
    println!("Summary: {}", item.summarize());
    item.display();
}



fn main() {
    let article = CCTV {
        author: "Sports editor".to_string(),
        content: "2024欧洲杯 聚焦绿茵盛宴!".to_string(),
    };

    notify(&article);
}
  • 运行结果:
Breaking news!
Summary: 2024欧洲杯 聚焦绿茵盛宴!, by Sports editor
Author: Sports editor
Content: 2024欧洲杯 聚焦绿茵盛宴!
// 定义两个trait,一个“总结”,一个“展示”
trait Summary {
    fn summarize(&self) -> String;
}
trait Display {
    fn display(&self);
}

// 定义结构体 CCTV
struct CCTV {
    author: String,   content: String,
}

// 为CCTV实现总结功能
impl Summary for CCTV {
    fn summarize(&self) -> String {
        format!("{}, by {}", self.content, self.author)
    }
}

// 为CCTV实现展示功能
impl Display for CCTV {
    fn display(&self) {
        println!("Author: {}", self.author);
        println!("Content: {}", self.content);
    }
}

// 定义Hacknews 结构体
struct Hacknews {
    username: String,
    content: String,
}
// 为Hacknews实现“展示功能”
impl Display for Hacknews {
    fn display(&self) {
        println!("Tweet by {}: {}", self.username, self.content);
    }
}

// 定义一个函数,接受实现了 Summary 和 Display traits 的对象作为参数
pub fn notify(item: &(impl Summary + Display)) {
    println!("Breaking news!");
    println!("Summary: {}", item.summarize());
    item.display();
}

fn main() {
    let article = CCTV {
        author: "Sports editor".to_string(),
        content: "2024欧洲杯 聚焦绿茵盛宴!".to_string(),
    };

    let hack = Hacknews {
        username: "Mako".to_string(),
        content: "fast, production-grade web bundler based on Rust (makojs.dev) ! from https://makojs.dev/blog/mako-open-sourced".to_string(),
    };

    notify(&article);
    // 需要多个trait都实现了才能运行
    // notify(&hack); // 报错 the trait bound 'Tweet:summary' is not satisfied ,the trait 'summary' is implemented for 'NewsArticle'
}

泛型中使用Trait

// 定义两个Trait
trait Printable {
    fn print(&self);
}

trait Drawable {
    fn draw(&self);
}

// 实现这两个Trait的类型
struct Circle {
    radius: f64,
}

impl Printable for Circle {
    fn print(&self) {
        println!("Circle with radius {}", self.radius);
    }
}

impl Drawable for Circle {
    fn draw(&self) {
        println!("Drawing a circle with radius {}", self.radius);
    }
}

// 函数接受实现了两个Trait的类型
fn print_and_draw<T>(item: &T)
where
    T: Printable + Drawable,
{
    item.print();
    item.draw();
}

fn main() {
    let c = Circle { radius: 3.5 };

    c.print(); // 输出: Circle with radius 3.5
    c.draw();  // 输出: Drawing a circle with radius 3.5

    print_and_draw(&c);
}

trait bound形式

  • 从以上的例子中可以发现。在 Rust 中,有两种主要的方式来约束泛型类型参数必须实现特定的 trait(特性):trait bound 形式和 impl Trait 语法糖形式。让我们来详细比较它们:

  • Trait Bound 形式:Trait bound 形式使用 where 子句来为泛型类型参数指定 trait 约束。例如:

fn example<T>(item: &T) -> usize
where
    T: Display + Clone,
{
    // 函数体
}
  • 这里 T: Display + Clone 表示泛型类型 T 必须同时实现 Display 和 Clone 这两个 trait。关键点在于 where 子句可以将多个 trait 约束放在一起,并且在使用泛型时可以非常清晰地看到这些约束。

  • impl Trait 语法糖形式

impl Trait 语法糖形式用于在函数签名中直接指定参数必须实现的一个或多个 trait。例如:

fn notify(item: &(impl Summary + Display)) {
    // 函数体
}
  • 这里 &(impl Summary + Display) 表示 item 参数必须实现 Summary 和 Display 这两个 trait。这种写法更加简洁和紧凑,适用于函数参数较少且只有少数几个约束的情况。

Ttait作为返回类型

在这里插入图片描述
在这里插入图片描述

#[derive(Trait)]

  • 在定义一些struct往往会有#[derive(Debug)]标签。Debug trait 是 Rust 标准库提供的一个 trait,用于以调试输出的格式打印类型的实例。当一个结构体或枚举被标记为 #[derive(Debug)] 时,Rust 编译器会自动为这个类型生成实现 Debug trait 的代码。这使得我们可以通过使用 {:?} 或者 println!("{:?}", value) 等方式打印这个类型的实例。

    #[derive(Debug)]
    struct MyStruct {
        field1: i32,
        field2: String,
    }
    
    • 在这个例子中,MyStruct 结构体通过 #[derive(Debug)] 派生了 Debug trait。这样,我们就可以使用 println!("{:?}", my_struct_instance) 来打印 MyStruct 的实例。
  • 更多相关 #[derive(Trait)]的内容可去了解一下过程宏,下面是一个例子,使得在主程序中可以使用宏 AnswerFn 来自动生成一个 answer() 函数,可以按照以下步骤进行:

第一步:创建 proc-macro crate
  1. 在一个新目录中创建一个 Cargo 项目:
cargo new proc-macro-examples --lib
  1. 将 Cargo.toml 文件中的内容更新为:
[package]
name = "proc-macro-examples"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

[dependencies]
# 没有依赖
  1. 更新 src/lib.rs 文件,添加 proc-macro 的实现:
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_derive(AnswerFn)]
pub fn derive_answer_fn(_item: TokenStream) -> TokenStream {
    "fn answer() -> u32 { 123 }".parse().unwrap()
}
第二步:创建使用宏的应用程序

接下来,创建一个使用 proc-macro crate 的 Rust 应用程序。这个应用程序将使用宏 AnswerFn 来为一个结构体自动生成 answer() 函数。

  1. 创建另一个新的 Rust 项目:
cargo new macro-app
  1. 更新 Cargo.toml 文件以依赖于我们刚刚创建的 proc-macro crate:
[package]
name = "macro-app"
version = "0.1.0"
edition = "2021"

[dependencies]
proc-macro-examples = { path = "../proc-macro-examples" }
  1. 更新 src/main.rs 文件,使用宏 AnswerFn:
extern crate proc_macro_examples;
use proc_macro_examples::AnswerFn;

#[derive(AnswerFn)]
struct Struct;

fn main() {
    assert_eq!(123, answer());
}
编译和运行
  • 先编译proc-macro-examples
cd proc-macro-examples
cargo build

然后,可以编译并运行应用程序:

cd macro-app
cargo run
  • 运行结果
PS C:\Users\kingchuxing\Documents\learning-libp2p-main\macro-app> cargo run
warning: `macro-app` (bin "macro-app") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.34s
     Running `target\debug\macro-app.exe`
PS C:\Users\kingchuxing\Documents\learning-libp2p-main\macro-app> 
rust笔记13:trait对象 在 Rust 中,trait 对象 是一种实现动态分发(dynamic dispatch)的机制,允许你在运行时处理实现了某个 trait 的不同类型。Trait 对象是 Rust 中实现多态性的重要工具之一,特别是在需要处理多种类型但又不确定具体类型的情况下。 阅读详情

相关推荐

STL文件救急指南:当你的SolidWorks打不开高版本文件时,这3种转换方法能保命

当SolidWorks无法打开高版本文件时,STL格式可作为应急转换的通用解决方案。本文详细介绍了三种核心转换方法:从源头获取高质量STL、借助第三方CAD软件或在线工具中转,以及优化内部协作流程。重点指导如何设置关键导出参数以控制精度,并强调STL转换是有损过程,应作为数据交换的最后手段。

perl8的博客 522

Rust特征(Trait)

如果不同的类型具有相同的行为,那么我们就可以定义一个特征,然后为这些类型实现该特征。定义特征是把一些方法组合在一起,目的是定义一个实现某些目标所必需的行为的集合。例如,我们现在有圆形和长方形两个结构体,它们都可以拥有周长,面积。因此我们可以定义被共享的行为,只要实现了特征就可以使用。// 为几何图形定义名为Figure的特征 fn girth(& self) -> u64;// 计算周长 fn area(& self) -> u64;// 计算面积 }

zy010101博客 2283

MicroDuck:面向具身机器人的Rust静态边缘运行时

边缘智能运行时是保障嵌入式AI系统实时性与安全性的核心基础设施。其本质是在资源受限设备上,为感知-决策-执行闭环提供可验证的确定性执行环境。关键技术原理包括编译期内存拓扑固化、最坏执行时间(WCET)静态分析、双Bank原子OTA升级等,共同支撑功能安全认证与低抖动控制。相比传统Linux+ROS或裸机C方案,它以Rust所有权模型实现零成本抽象与内存安全契约,显著降低实时系统开发门槛。典型应用场景涵盖AGV导航、巡检机器人、教育人形平台等对确定性有严苛要求的具身智能终端。MicroDuck正是这一范式的工

weixin_33834137的博客 461

弄懂Rust编程中的Trait

trait 定义了某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共享的行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型。

这里是二进制空间安全博客,主要分享网络安全、信息安全和数据安全相关的技术文章。内容覆盖编程语言、基础知识、漏洞分析、攻防技巧、安全工具使用、最佳实践等安全技术主题。 1389

开源libmodbus编译为32位和64位动态库

libmodbus 是支持Linux,Mac OS X,window 的一个开源库,支持modbus TCP和RTU 两种模式。

lemontree1945的博客 1922

【从零开始学Skynet】基础篇(一):Skynet环境搭建

Skynet运行于Linux操作系统,我们可以在自己的电脑上搭建虚拟机系统,也可以购买阿里云、腾讯云服务器,笔者这个系列的所有代码都是在Ubuntu16.04版本的虚拟机系统下运行编辑。

我是一条寻水的鱼 3167

Rust学习笔记007-所有权

什么是所有权 Rust的核心功能(之一)就是所有权,其令 Rust 无需垃圾回收即可保障内存安全。 所有运行的程序都必须管理其使用计算机内存的方式: 一些语言中具有垃圾回收机制,在程序运行时不断地寻找不再使用的内存; 在另一些语言中,程序员必须亲自分配和释放内存。 Rust 则选择了第三种方式:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。在运行时,所有权系统的任何功能都不会...

MARATRIX BLOG 1352

【opencv3 学习记录】第二章 读取显示保存视频

一:捕获视频函数 1.函数:cv2.VideoCapture(参数) 2.参数说明: (1)开启摄像头:参数一般为0,你可以通过设置成 1 或 者其他的来选择别的摄像头。 (2)从文件夹中获取视频:参数为字符串形式的文件路径 3.示例: cap = cv2.VideoCapture(0) #cap:存放参数 二:读取视频函数 1.函数:cap.read() 2.函数说明: (1)cap.read 中cap与捕获视频函数存放函数一致,可以自己命名.括号一般不用填写 (2)ret,f

m0_64448543的博客 3272

【百例RUST - 007】结构体

rust 结构体用法

浪客川 81

【Labview与SQL Server互联(labview可以引用数据库)】

Labview与SQL Server互联

Magize的博客 3585

CocosCreator3.8.2实战:5分钟搞定多分辨率适配与横竖屏自动翻转(附完整Demo)

本文针对CocosCreator3.8.2开发者,提供了一套5分钟快速集成、开箱即用的多分辨率屏幕适配与横竖屏自动翻转解决方案。通过封装好的ScreenAdapter组件,开发者无需处理复杂计算,即可实现等比缩放或拉伸全屏两种主流适配模式,并自动响应设备旋转,有效解决移动端UI在不同屏幕比例和方向下的显示问题。文末附完整Demo。

z4a5b6的博客 723

rust通过trait默认方法,实现一些公共函数

摘要:这段Rust代码定义了一个BaseEntitySingle trait,提供JSON序列化/反序列化等方法,并通过ConfigDto结构体实现该trait。ConfigDto包含Redis、软件、数据库等配置字段。测试代码演示了配置对象的JSON转换:先将对象序列化为JSON字符串,修改字段值后,再从JSON反序列化回对象,验证了字段值变更的正确性。结果输出显示dbType字段成功从"1111"修改并保持状态。

leijmdas的专栏 50

Alibaba Java Coding Guidelines,以后我的Java代码规范,就靠它了

前言 对于Java代码规范,业界有统一的标准,不少公司对此都有一定的要求。但是即便如此,庞大的Java使用者由于经验很水平的限制,未必有规范编码的意识,而且即便经验丰富的老Java 程序员也无法做到时刻将规范牢记于心。所以对于代码规范扫描工具,一经问世就广受青睐,阿里巴巴出品的Alibaba Java Coding Guidelines(阿里巴巴Java代码规约扫描,以下简称为AJCG)插件便是其...

java梦工厂 859

Spacedrive Syncable Trait 深度解析:基于所有权模型的跨设备同步框架

Spacedrive 是一个以 Rust 实现虚拟分布式文件系统的跨平台文件浏览器,其同步基础设施采用无领导(leaderless)混合架构。`Syncable` trait 是该同步体系的核心抽象——它为数据库模型提供统一的同步能力,并依据"设备拥有(device-owned)与共享(shared)"的所有权分类自动选择状态广播(state-based)或 HLC 日志(log-based)两种

gitblog_01155的博客 624

继电保护原理1.2-反时限过流保护

反时限过流保护

让你爱上电路设计 1万+

【异常】安装OpenClaw遇到 Windows环境pnpm安装node-llama-cpp postinstall生命周期脚本执行失败完整解决方案

摘要: Windows环境下使用pnpm安装node-llama-cpp时,postinstall脚本执行失败(错误码3221225477),主要因缺少C++编译工具链或预构建二进制下载失败。解决方案: 基础排查:确保管理员权限、Node.js ≥18、路径无中文; 安装编译工具:推荐Visual Studio的“C++桌面开发”组件或windows-build-tools; 环境变量配置:强制CPU模式+国内镜像(NODE_LLAMA_CPP_FORCE_CPU=true,镜像地址替换为国内源); pnp

奶爸的编程之路,也就一周冷个三天 618

007 通过链表学Rust之支持泛型

介绍 视频地址:https://www.bilibili.com/video/av78062009/ 相关源码:https://github.com/anonymousGiga/Rust-link-list 详细内容 本节我们让我们的链表支持泛型。首先修改我们的定义如下: pub struct List<T> { head: Link<T>, } type Link<T> = Option<Box<Node<T>>>; struc

令狐一冲 203

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Rust编程基础到进阶

Rust编程视频教程(基础) 01 001rust语言以及课程介绍.mp4 02 002环境搭建以及hello.mp4 03 003变量.mp4 04 004类型.flv 05 005函数.mp4 06 006注释.mp4 07 007控制流.mp4 08 008所有权.mp4 09 009引用.mp4 10 010slice.mp4 11 011结构体.mp4 12 012方法.mp4 13 013枚举类型与匹配.mp4 14 014Option.mp4 15 015Option2.mp4 16 016v

mhx123456789的博客 462

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Rust:String

本文讲解Rust的String,包含编码原理、增删查改、内部结构、内存分配、转换构造、查找匹配、迭代器与Trait实现

博客网站 https://async-area.com 509

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Base-GPUI:在GPU加速的Rust原生GUI中复用Base UI组件逻辑

在桌面应用开发领域,组件库是提升开发效率、确保交互一致性的关键技术。其核心原理在于将常见的UI元素(如按钮、下拉框、模态框)的交互逻辑、状态管理和可访问性支持封装为可复用的模块,开发者只需关注业务逻辑和视觉样式。这种“无头”架构将行为与表现分离,为高性能应用开发提供了灵活基础。在Rust生态中,GPUI框架凭借GPU加速渲染能力,为构建高性能原生应用提供了新选择。Base-GPUI项目正是将成熟的Base UI无头组件库移植到GPUI框架的实践,它解决了Rust高性能GUI生态中缺乏高级组件库的痛点,让开发

weixin_33868027的博客 398

Rust GUI开发新思路:基于GPUI框架的无头组件实践指南

在现代GUI开发中,无头组件架构通过分离交互逻辑与视觉样式,为构建灵活、可维护的界面系统提供了新范式。这种设计模式源于前端领域的关注点分离思想,其核心原理是将组件的状态管理、事件处理和可访问性等行为逻辑封装为独立模块,而将样式渲染权完全交给开发者。这种架构的技术价值在于提升代码复用性、简化设计系统定制,并确保跨平台应用的一致性交互体验。在桌面应用、设计工具和跨平台解决方案等场景中,无头组件能显著加速开发流程。本文将聚焦于Rust生态下的GPUI框架,探讨如何将React生态中成熟的Base UI无头组件库理

weixin_34090562的博客 338

windows-rs 中的 windows-reference:用 Rust 实现 WinRT `IReference<T>` 装箱值类型

> 本文以 windows-rs 仓库中 [crates/libs/reference/readme.md](https://link.gitcode.com/i/bd2f1e96fe7c75ce0c5e6e333bb06d25) 为主线,深入讲解 `windows-reference` crate 如何为 WinRT 提供 `IReference<T>` 的 Rust 装箱实现。读完本文,你将掌

gitblog_00800的博客 373

Rust构建终端安全工具Tirith:防御同形攻击与AI指令注入

在终端安全领域,同形攻击和AI指令注入是两类日益突出的威胁。同形攻击利用Unicode字符的视觉相似性进行伪装,而AI指令注入则通过劫持大语言模型的输出来夹带恶意命令。这些攻击的核心在于绕过用户的视觉审查和信任机制,直接在最底层的命令行界面执行危险操作。从技术原理看,防御这类威胁需要结合字符编码分析、模式匹配和实时检测能力。Rust语言凭借其内存安全、零成本抽象和高性能的特性,成为构建此类安全工具的绝佳选择。它能在编译期消除内存错误,确保安全工具自身可靠,同时以近乎原生代码的效率运行,满足终端实时检查的苛刻

weixin_30607659的博客 433

Dism++ C 盘空间回收实操手册:3 条路线腾出数 GB,系统安全上保险

C 盘接近爆满、Windows 更新卡死、系统越用越慢,需要的不是又一个清洁器,而是一个直接干到系统层的维护工具。Dism++ 是一款免费、绿色、开源的系统维护工具,深度空间回收、系统压缩、补丁管理、系统完整备份与还原,都能自己上手。 ## 它替你管什么 - **办公族,C 盘反复告急**:WinSxS 旧组件、浏览器旧备份、事件日志这些普通清理工具扫不到的文件,一次扫描就能列出来处理掉。 -

gitblog_00955的博客 470

基于 WebAssembly 的 Linera 链上 Web 客户端:`@linera/client` 集成指南与 Signer 签名体系实战

`@linera/client` 是 Linera 协议官方发布到 NPM 的浏览器端 Web 客户端包(对应仓库中的 `web/@linera/client` 目录,Rust crate 名为 `linera-web`)。它把 Linera 客户端的 Rust 核心编译为 WebAssembly,并辅以 TypeScript 类型的 JavaScript 封装,让前端应用能够直接创建链、查询余额

gitblog_00279的博客 1016

<crate-name>

一两句话。这个 crate 解决什么问题? ## What this crate is allowed to depend on 列出该 crate 可导入的依赖。要明确。 如果某个依赖未被列出,没有 ADR 就不要添加。 ## Extension points 在哪里可以添加新实现?实现哪个 trait? 链接到相关 trait。 ## What does NOT belong here

gitblog_00377的博客 9
上一篇: 电路笔记(PCB):电流容量(IPC-2221和IPC-2152)/载流公式+阻抗匹配
下一篇: p2p、分布式,区块链笔记: 通过libp2p的Kademlia网络协议实现kv-store
FakeOccupational
博客等级 码龄6年 2万+粉丝 1727原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值