Rust之结构体(三):方法

Rust 中级教程 第5课——trait(3) 看到这里,我想大家应该对 trait都有了初步的了解了。本篇文章将向大家介绍下在 Rust 标准库中常用和常见的一些 trait。 阅读详情

开发环境

  • Windows 10
  • Rust 1.58.1

 

  • VS Code 1.63.2

 项目工程

这里继续沿用上次工程rust-demo

方法

方法类似于函数:它们用fn关键字和它们的名称声明,它们可以有参数和返回值,并且它们包含一些从其他地方调用时运行的代码。然而,方法不同于函数,因为它们是在结构(或枚举或特征对象)的上下文中定义的,并且它们的第一个参数总是self,它代表方法被调用的结构的实例。

定义方法

这里我们更改之前的矩形实例作为参数的面积函数,改为在矩形结构上定义面积方法,代码如下:

// debug模式
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

// 关键字impl
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    // 调用方法
    println!("The area of the rectangle is {} square pixels.", rect1.area());             
}

运行

cargo run

 

 为了在Rectangle的上下文中定义函数,我们为矩形启动一个impl(实现)块。这个impl块中的所有内容都将与矩形类型相关联。然后,我们在impl花括号内移动面积函数,并将第一个(在这种情况下,只有一个)参数更改为签名中和正文中的self。在main中,我们调用了area函数并将rect1作为参数传递,我们可以使用方法来调用Rectangle实例上的area方法。调用方式:

实例.方法(参数)

在签名区域,我们使用&self代替&Rectangle。&self实际上是self:&Self的简称。在impl块中,类型Self是impl块所属类型的别名。方法的第一个参数必须有一个名为self类型的self的参数,因此Rust允许您在第一个参数点仅使用Self的名称来缩写这个参数。请注意,我们仍然需要在self速记前面使用&来表示这个方法借用了Self实例,就像我们在rectangle:&Rectangle中所做的那样。方法可以拥有self,像我们在这里做的那样不变地借用self,或者可变地借用self,就像它们可以借用任何其他参数一样。 

我们在这里选择&self的原因与我们在函数版本中使用&Rectangle的原因相同:我们不想获得所有权,我们只想读取结构中的数据,而不是向其写入数据。如果我们想改变调用方法的实例,作为方法的一部分,我们将使用&mut self作为第一个参数。很少有方法通过仅使用self作为第一个参数来获得实例的所有权;当方法将self转换为其他东西,并且您希望防止调用方在转换后使用原始实例时,通常会使用这种技术。

除了使用方法和不必在每个方法的签名中重复self类型之外,使用方法代替函数的主要好处是有利于组织。我们已经将一个类型实例的所有功能都放在一个impl块中,而不是让未来的代码用户在我们提供的库中的不同位置搜索Rectangle的功能。

请注意,我们可以选择给一个方法与结构的一个字段同名。例如,我们可以在Rectangle上定义一个方法,也称为width,示例如下:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

// 方法名width和字段名width同名
impl Rectangle {
    fn width(&self) -> bool {
        self.width > 0
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    if rect1.width() {  // 调用方法
        println!("The rectangle has a nonzero width; it is {}", rect1.width);       // 访问字段
    }
}

编译运行

cargo run

 结果:

这里,我们选择将width方法的行为设置为:如果实例的width字段中的值大于0,则返回true如果该值为0,则返回false:我们可以在同名方法中使用字段来实现任何目的。总的来说,当我们在rect1.width后面加上括号时,Rust知道我们指的是方法宽度。当我们不使用括号时,Rust知道我们指的是字段宽度。

通常,但不总是,与字段同名的方法将被定义为只返回字段中的值,而不做其他事情。像这样的方法被称为getters,Rust不会像其他语言那样为结构字段自动实现它们。Getters很有用,因为您可以将字段设为私有,而将方法设为公共,从而作为类型公共API的一部分实现对该字段的只读访问。后续会研究公有,私有。

->运算符呢?

在C和C++中,两种不同的运算符用于调用方法:您使用。如果直接在对象上调用方法,并且->如果在指向对象的指针上调用方法,并且需要先取消引用指针。换句话说,如果对象是指针,object->something()类似于(*object).something()。

Rust没有一个等价于->的运算符;相反,Rust有一个叫做automatic referencing and dereferencing的特性。调用方法是Rust中少数几个有这种行为的地方之一。

它的工作原理是这样的:当你用object.something()调用一个方法时,Rust会自动添加&、&mut或*以便object与方法的签名相匹配。换句话说,以下是相同的:

p1.distance(&p2);
(&p1).distance(&p2);

第一个看起来干净多了。这种自动引用行为之所以有效,是因为方法有一个明确的接收者——self类型。给定一个方法的接收者和名称,Rust可以明确地判断该方法是读取(&self)可变(&mut self)还是消费(self)。事实上,Rust让方法接受者隐含了借用,这是让所有权在实践中符合人体工程学的一个重要部分。

具有更多参数的方法

让我们通过在Rectangle结构上实现第二个方法来练习使用方法。这一次,我们希望Rectangle的一个实例采用Rectangle的另一个实例,如果第二个Rectangle可以完全适合self,则返回true否则它应该返回false。示例如下:

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };
    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}

希望输出如下,因为rect2的两个维度都小于rect1的维度,但是rect3比rect1宽

Can rect1 hold rect2? true
Can rect1 hold rect3? false

我们知道我们想要定义一个方法,所以它将在impl Rectangle块中。方法名将是can_hold,它将采用另一个Rectangle的不可变借用作为参数。我们可以通过查看调用方法的代码来判断参数的类型:rect1.can_hold(&rect2)传入&rect2,这是对rect2的不可变借用,rect2是Rectangle的一个实例。这很有意义,因为我们只需要读取rect2(而不是写入,这意味着我们需要一个可变的借用),我们希望main保留rect2的所有权,这样我们就可以在调用can_hold方法后再次使用它。can_hold的返回值将是一个布尔值,实现将检查自身的宽度和高度是否都分别大于另一个矩形的宽度和高度。can_hold方法如下:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // can_hold方法
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };
    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}

编译运行

cargo run

 当运行上述代码时,我们会得到我们想要的输出。方法可以接受我们在self参数之后添加到签名中的多个参数,这些参数就像函数中的参数一样工作。

关联函数

impl块中定义的所有函数都称为关联函数,因为它们与以impl命名的类型相关联。我们可以定义没有self作为第一参数的关联函数(因此不是方法),因为它们不需要类型的实例来工作。我们已经使用了一个如String::from的函数,函数,它是在String类型上定义的。

不是方法的关联函数通常用于将返回结构的新实例的构造函数。例如,我们可以提供一个关联函数,该函数将有一个维度参数,并将其用作宽度和高度,这样就可以更容易地创建一个方形Rectangle,而不必指定相同的值两次,如下所示:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

// square方法
impl Rectangle {
    fn square(size: u32) -> Rectangle {
        Rectangle {
            width: size,
            height: size,
        }
    }
}

fn main() {
    println!("square call");
    let sq = Rectangle::square(3);
    println!("{} {}", sq.width, sq.height);
}

编译运行

要调用这个关联的函数,我们使用带有结构名的::语法;如let sq = Rectangle::square(3);就是一个例子。此函数由struct:命名空间隔开::语法用于关联函数和模块创建的命名空间。

多个impl块

每个结构允许有多个impl块。例如,上述代码可以修改为如下:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

// area的impl块
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

// can_hold的impl块
impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };
    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}

编译运行

 这里没有理由将这些方法分成多个impl块,但这是有效的语法。后续还会进一步讨论。

总结

结构体允许创建对自身的域有意义的自定义类型。通过使用结构体,您可以将关联的数据片段保持相互连接,并为每个片段命名以使代码清晰。在impl块中,您可以定义与您的类型关联的函数,而方法是一种关联函数,允许您指定结构实例的行为。

但是结构体并不是创建自定义类型的唯一方法:让我们转向Rust的枚举特性,向工具箱添加另一个工具。

本章重点

  • 方法的概念
  • 方法的定义 - impl
  • 方法的调用
Rust---#[derive(Debug)] 当你定义一个结构体或枚举时,可以在其前面加上x: i32,y: i32,Up,Down,Left,Right,如果需要更细粒度的控制如何格式化输出,可以手动实现,而不是使用。在这种情况下,不适用。age: u8,// 手动实现 Debug trait// 只打印名字write!age: 30,// 使用 {:?} 打印 Debug 格式println!("{:?如果使用来自动派生age: u8,age: 30,println!("{:? 阅读详情

相关推荐

Rust---方法(Method)

另外,在 中,可以为一个类型实现多个 块,每个 块可以包含不同的方法或关联函数。这样可以将相关的方法组织在一起,使代码更具可读性和可维护性。函数():方法():总的来说,函数是独立的代码单元,而方法是与特定类型相关联的函数。在中,方法是通过块实现的,而函数则是独立存在的。方法在被调用时,具有隐含的参数,普通的函数不会有 参数,因为它们不与特定的实例相关联。通过方法,可以实现面向对象编程中的封装和多态特性。 self、&self 和 &mut self 在 中, 是用来表示方法的接收者()的参数,它

weixin_45880844的博客 485

Rust中`#[derive(Debug)]`让编译器实现Debug特性

在上述示例中,我们定义了一个 `Person` 结构体,并使用 `#[derive(Debug)]` 属性自动生成实现 `Debug` trait 的代码。在上述示例中,我们定义了一个 `Person` 结构体,并使用 `#[derive(Debug)]` 自动生成实现 `Debug` trait 的代码。` 宏打印 `person` 的值。}` 中,`:` 表示格式化指示符的开始,`?可以看到,通过自动生成的 `Debug` 实现,我们可以以可读的方式打印 `Person` 结构体的字段和值。

weixin_37841024的博客 1552

【Rust结构体】Rust结构体详解:从基础到高级应用

结构体(struct)是Rust中一种自定义数据类型,它允许你将多个相关的值组合在一起,形成一个有意义的组。结构体是创建更复杂数据类型的基础,也是面向对象编程中"对象"概念的基石。 与元组类似,结构体的每个部分可以是不同类型。但与元组不同,结构体需要为每个部分命名,这使得数据访问更加清晰明确。

景天科技苑 5万+

Rust 中Self 关键字的两种不同用法

这里的 self 表示方法接收者。时,它代表的是当前实现这个方法的结构体或枚举类型本身。所以在这个上下文中,创建了一个新的结构体实例,并初始化了所有字段。是结构体或枚举类型的占位符。的返回类型和内部实例化部分使用。

日拱一卒,玉汝于成 1898

猿创征文 | 【Rust指南】解析struct 结构体的定义、实例化、方法、所有权、关联函数

书接上文,本篇博客要分享的是Rust 中和结构体有关的知识,包括定义、实例化的特定,方法的格式、所有权问题以及关联函数。所以此篇文章还会涉及到前面讲的Rust 基本数据类型、所有权等知识,大家在对某些知识点感到陌生的时候可以参考此专栏以往的文章。............

叶落秋白的博客 2937

Unity抖音小游戏上架实战:从零到一,详解流程与避坑指南

本文详细介绍了Unity抖音小游戏上架的全流程,包括环境准备、SDK集成、开发者账号注册、软著申请、打包提交流程及常见问题解决方案。重点解析了抖音小游戏平台特有的配置细节和避坑技巧,帮助开发者高效完成游戏上架并优化用户体验。

weixin_33704234的博客 261

Rust对象之结构体,枚举,特性

Rust中的结构体(Struct)与元组(Tuple)都可以将若干个类型不一定相同的数据捆绑在一起形成整体,但结构体的每个成员和其本身都有一个名字,这样访问它成员的时候就不用记住下标了。元组常用于非定义的多值传递,而结构体用于规范常用的数据结构。结构体的每个成员叫做"字段"。结构体定义,注意:结尾不需要;符号,而且每个字段定义之后用分隔found: u32Rust 枚举的每个变体(variant无数据元组式数据结构体式数据。三种可以在同一个枚举里混用。Quit, // 无数据(类似单元结构体)

上善若泪 234

银河麒麟V10离线环境下的Python项目迁移:从Windows依赖到ARM架构适配

本文详细介绍了在银河麒麟V10离线环境下将Python项目从Windows迁移到ARM架构的完整流程。重点讲解了离线安装pip、virtualenv等基础工具的方法,以及如何解决ARM架构兼容性问题,确保项目依赖正确迁移。文章还提供了常见问题解决方案和性能优化建议,帮助开发者顺利完成国产化平台适配工作。

weixin_42639246的博客 423

Rust生命周期管理详解

这里`<'a>`声明了一个生命周期参数,`&'a str`表示引用必须至少存活生命周期`'a`。生命周期之间存在子类型关系:如果生命周期`'a`比`'b`更长(即`'a`包含`'b`),我们说`'a`是`'b`的子类型(`'a: 'b`)。在这个函数中,我们同时使用了生命周期参数`'a`和泛型类型参数`T`,并通过trait约束指定`T`必须实现`Display` trait。这里`'a: 'b`约束表示生命周期`'a`至少和`'b`一样长,确保`Parser`中的引用始终有效。

cuffpp_497的博客 200

美团外卖 mtgsig 1.2 逆向工程与补环境实战指南

本文深入解析了美团外卖核心风控参数mtgsig 1.2的生成机制与逆向实战。通过拆解其复杂的JSON结构,揭示了设备指纹、环境信息加密等关键字段。重点阐述了在Node.js中模拟浏览器环境(补环境)的核心方法,包括DOM/BOM对象、本地存储及Canvas/WebGL等高级指纹的模拟技巧,为安全研究和合规自动化测试提供了一套完整的技术指南。

uber9的博客 410

opencv-meshgrid

使用opencv::repeat函数和std::iota函数完成meshgrid功能。 X Y Z 通俗的说就是根据Z的大小生成X矩阵,Y矩阵

yuegooxi的博客 1607

Rust 数据类型 之 结构体(Struct)

结构体(Struct)是一种自定义数据类型,允许将多个相关的值组合在一起,形成一个更复杂的数据结构。结构体被广泛应用于组织和管理数据,具有灵活性和强大的表达能力。在Rust中,定义和声明结构体的语法如下: struct Name { field1: Type1, field2: Type2, // ... fieldN: TypeN, }

汉阳Hann's Home 6万+

【图像压缩】超先验模型 《VARIATIONAL IMAGE COMPRESSION WITH A SCALE HYPERPRIOR》

绪论 2015年,第一个端到端图像编码方案被提出。基于深度学习的端到端图像压缩主要分为两类,一类是基于RNN的方法,一类是基于CNN的方法。本文对基于CNN的方法

hahalidaxin的专栏 1万+

Rust中结构体的定义和实例化

一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 键-值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。 声明一个特定的用户: 为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用

write less , do more 6213

别再只盯着时序了!聊聊SDC里那些容易被忽略的‘配角’命令:工作条件、线载模型与面积约束

本文深入探讨了SDC(设计约束)中常被忽视的关键命令,包括set_operating_conditions、set_wire_load_model和set_max_area。这些‘配角’命令在芯片设计中扮演着至关重要的角色,影响时序收敛、功耗和面积优化。文章通过实际案例和最佳实践,揭示了如何正确配置工作条件、选择线载模型以及动态调整面积约束,以提升设计质量和效率。

weixin_26875109的博客 208

MATLAB与ROS联合仿真——ROS环境搭建及相关准备工作(上)

本篇文章主要介绍在安装完ROS后,在进行MATLAB与ROS联合仿真之前,需要进行的一些环境搭建以及准备工作,主要分为 创建ROS工作空间及功能包、必备功能包安装、安装Gazebo11、导入实验功能包至工作空间、安装Visual_Studio_Code(选做)、常用便捷工具安装(选做) 六部分。    本部分内容共分为上下两篇,上篇包括创建ROS工作空间及功能包和必备功能包安装这两部分,下篇包括、安装Gazebo11、导入实验功能包至工作空间、安装Visual_Studio_Code(选做)、常用便捷工

慕羽★的博客 3362

Rust结构体讲解学习,以及impl结构体方法和结构体关联函数

found: u32注意:如果你常用 C/C++,请记住在 Rust 里 struct 语句仅用来定义,不能声明实例,结尾不需要;符号,而且每个字段定义之后用 , 分隔。

1757

Kimodo 入门教程(一)英伟达开源人形机器人动捕数据集训练运动学动作扩散模型

Kimodo是一个基于700小时商用光学动作捕捉数据集训练的运动学动作扩散模型,能够生成高质量的人体和机器人3D动作。该模型支持通过文本提示和多种约束条件(如关键帧、末端执行器位置等)进行控制,并提供数字人类和类人机器人两种模型变体。安装方式包括软件包安装和源代码安装两种,需要配置HuggingFace令牌以访问文本编码器。推荐使用GPU加速,最低需要17GB显存。项目提供命令行生成和交互式演示两种使用方式,演示程序支持时间轴编辑和实时3D可视化。模型分为商用友好版和受限版,其中SMPL-X版本需要额外申请

2506_90492529的博客 1932

Rust-结构体

我们定义一个结构体Rectangle​ ,这个结构体表示的是一个矩形,它有着 width 和 height 两个元素(字段)。我们现在要给这个结构体专门定义一个“方法”,用以计算矩形的面积。当我们为一个给定的结构体定义方法时,需要添加impl​关键字,也就是在impl块​中编写结构体的一些方法。另外,一个结构体可以有多个impl块​存在。在下面的代码中,我们给Rectangle​ 结构体上成功定义了area​ 方法,用来计算矩形的面积。

日拱一卒无有尽,功不唐捐终入海 1589

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Rust 语言中的结构体

结构体和我们之前论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。定义结构体,需要使用struct关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为字段fieldage: u64,

专注于大数据方向,区块链,前后端,数据可视化,人工智能等领域 2396

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

详解Rust结构体struct用法

Rust的结构体(struct)是一种自定义的数据类型,允许开发者命名和包装多个相关的值,以形成有意义的数据组合。在Rust中结构体不仅用于数据组织,还密切结合了Rust的内存安全性和所有权模型特性,在开发系统编程过程中很有用。

yang1fei2的博客 1836

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【Rust】结构体

结构体和元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。定义结构体,需要使用struct关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,称为字段。一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的实例。

m0_72516377的博客 1377

【Rust】005-Rust 结构体

/ 定义一个元组结构体,用于表示二维向量// 为Vector2D实现Add特征,实现向量相加功能// 向量1// 向量2// 向量相加println!// 定义一个结构体 Rectangle,用于表示矩形width: u32, // 矩形的宽度,类型为 u32height: u32, // 矩形的高度,类型为 u32// 为结构体 Rectangle 实现方法// 定义一个方法 area,用于计算矩形的面积。

訾博(ZiBo)的博客 1341

【Rust】——结构体struct

目录 🎯定义并实例化struct 🥽什么是struct 🥽定义struct 🥽实例化struct 🎯struct例子 🎯struct 🥽struct方法 🥽方法调用的运算符 🥽方法参数 🥽关联函数 🥽多个impl块

shsjssnn的博客 2621

Rust结构体详解:定义、使用及方法

Rust结构体详解:定义、使用及方法

一起coding,一起嗨。 1515

Rust 结构体

Rust 的结构体(Struct)是一种用户定义的复合数据类型,用于将多个相关字段组织在一起。Rust 提供三种结构体类型:经典结构体(具名字段)、元组结构体(无名字段)和单元结构体(无字段)。结构体支持方法定义,常与impl块和所有权规则结合使用。Rust 的结构体是组织和管理数据的核心工具,支持经典结构体、元组结构体和单元结构体三种形式。结合所有权、借用和生命周期,结构体提供了安全高效的数据操作方式。特性描述示例经典结构体具名字段,适合复杂对象元组结构体无名字段,通过索引访问单元结构体。

m0_57545130的博客 1046
上一篇: Rust之结构体(二):结构体示例
下一篇: Rust之枚举和模式匹配(一):枚举定义
枫★曦
博客等级 码龄19年 251粉丝 153原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值