Dart基础学习总结(下)

本文详细介绍了Dart编程中的面向对象特性,包括静态成员、类的继承、抽象类、多态以及接口的使用。此外,还深入探讨了Dart的泛型,包括泛型方法、泛型类以及自定义泛型类的应用。同时,讲解了Dart中的库管理和导入,如自定义库、系统库和第三方库的使用,以及异步编程的Async Await概念。

目录

Dart 类中的静态成员 静态方法

Dart中的静态成员:

Dart中的对象操作符

面向对象的三大特性:封装 、继承、多态

Dart中的类的继承: 

super关键词的使用

子类里面调用父类的方法

Dart中的抽象类 多态 以及接口

Dart中的抽象类

Dart中多态

接口

接口 文件分离

Dart中implements实现多个接口

Dart中的mixins   with的使用

mixins的实例类型是什么?

Dart中的泛型

泛型方法

 泛型类

自定义一个泛型类

泛型接口

Dart中的库 自定义库、系统库、第三方库

Dart中的库

 Dart中导入自己本地库

导入系统内置库 math库 

导入系统内置库实现请求数据httpClient

关于 Async Await

Dart 导入Pub包管理系统中的库

Dart库的重命名  Dart冲突解决

库的部分导入

 延迟加载


Dart 类中的静态成员 静态方法

Dart中的静态成员:

  1、使用static 关键字来修饰的变量和函数就称为静态属性或函数 

  2、静态方法不能访问非静态成员,非静态方法可以访问静态成员

 class Person {
//用static修饰的就是静态成员
   static String name = '张三';
   static void show() {
     print(name);
   }
 }

 main(){
   //调用静态方法或属性的时候,不能用实例化一个对象来调用
   //而是直接通过类名.属性或类名.方法名()的形式来访问
   print(Person.name);
   Person.show(); 

 }

对于静态方法不能访问非静态成员,非静态方法可以访问静态成员的理解

class Person {
  static String name = '张三';//静态属性
  int age=20;                //非静态属性

  static void show() {       //静态方法,可以直接访问静态属性
    print(name);
  }

  void printInfo(){          /*非静态方法可以访问静态成员以及非静态成员*/
       print(name);          //访问静态属性
       print(this.age);      //访问非静态属性
       show();               //调用静态方法
  }

  static void printUserInfo(){//静态方法
        print(name);          //静态属性
        show();               //静态方法
       //print(this.age);      //静态方法没法访问非静态的属性
       //this.printInfo();     //静态方法没法访问非静态的方法
       //printInfo();
  }
}


main(){
   //调用静态的属性和方法
   print(Person.name);
   Person.show();

   //调用非静态的属性和方法
   Person p=new Person();
   p.printInfo();
   Person.printUserInfo();
}

Dart中的对象操作符

    ?     条件运算符 (了解)

    as    类型转换

    is    类型判断

    ..    级联操作 (连缀)  (记住)


 

class Person {
  String name;
  num age;
  Person(this.name,this.age);
  void printInfo() {
    print("${this.name}---${this.age}"); 
  }
}

main(){
//------?.条件运算符的使用
   Person p;          //在这里定义一个变量p,没有对它进行初始化
   p.printInfo();     //若直接使用p.printInfo时,就会报错
   p?.printInfo();    //但是加上?号以后,就不会报错,此时表示,若p为空则不执行后面的方法
  
   Person p=new Person('张三', 20);//给p赋值以后
   p?.printInfo();                //此时就可以正常打印:张三---20


//------is类型判断的使用
    if(p is Person){ //判断p是不是属于Person类
         p.name="李四";
     }

     p.printInfo();
     print(p is Object);//输出结果:true,因为dart中所有类都是object的子类
 

//------as类型转换的使用
     var p1;
     p1 = Person('张三1', 20);

    (p1 as Person).printInfo();//将p1强制转化成Person类型,可防止程序运行出错

  ..    级联操作 (连缀) 使用的比较多的一种操作:

   Person p1=new Person('张三1', 20);
   p1.printInfo();//输出结果:张三1---20
   /*级联操作示例*/
   p1..name="李四"
     ..age=30
     ..printInfo();//输出结果:李四---30

面向对象的三大特性:封装 、继承、多态

Dart中的类的继承: 

    1、子类使用extends关键词来继承父类

    2、子类会继承父类里面可见的属性和方法 但是不会继承构造函数

    3、子类能复写父类的方法 getter和setter

class Person {
  String name='张三';
  num age=20;
  void printInfo() {
    print("${this.name}---${this.age}"); 
  }
}

class Web extends Person{
}

main(){  

  Web w=new Web();
  print(w.name);
  w.printInfo();//虽然Web类什么都没做,但是依然可以打印出来张三---20

}

super关键词的使用

class Web extends Person{
  //根据系统提示,会自动生成下面语句
  //因为构造函数不能被继承,所以这里创建了web类的构造函数
  //通过super关键字把值付给父类
  Web(String name, num age) : super(name, age){

  }
}

当然Web类继承Person后,还可以写自己的属性和方法。如:

class Web extends Person{
  //除了父类的两个属性,还可以直接添加自己的属性,sex
  String sex;
  Web(String name, num age,String sex) : super(name, age){
    this.sex = sex
  }
   //还可以写自己的方法
  printWebInfo(){
     print("${this.name}---${this.age}---${this.sex}"); 
}
   
}

main(){
  //在实例化的时候也要传入三个参数
  Web w=new Web('张三', 12,'男');
  w.printInfo();//输出结果:张三---12
  w.printWebInfo();//输出结果:张三---12---男

}

在子类里面,不仅可以继承父类,扩展父类,还可以复写父类的方法

class Person {
  String name;
  num age;

  Person(this.name,this.age);

  void printInfo() {
    print("${this.name}---${this.age}"); 
  }

  work(){
    print("${this.name}在工作...");
  }
}



class Web extends Person{

  Web(String name, num age) : super(name, age);

  run(){
    print('run');
  }
  //覆写父类的方法
  @override       //可以写也可以不写  建议在覆写父类方法的时候加上 @override
  void printInfo(){
     print("姓名:${this.name}---年龄:${this.age}");
  }

  @override
  work(){
    print("${this.name}的工作是写代码");
  }

}


main(){

  Web w=new Web('李四',20);
 //执行的时候会优先找子类里的方法,没有才会执行父类里的方法
  w.printInfo();
  w.work();

}

子类里面调用父类的方法

class Person {

  String name;
  num age;

  Person(this.name,this.age);

  void printInfo() {
    print("${this.name}---${this.age}"); 
  }

  work(){
    print("${this.name}在工作...");
  }

}


class Web extends Person{

  Web(String name, num age) : super(name, age);

  run(){

    print('run');
    super.work();  //自类调用父类的方法,通过super关键字调用

  }

}


main(){

  Web w=new Web('李四',20);
  w.printInfo();
  w.run();输出结果:run  李四在工作

}

Dart中的抽象类 多态 以及接口

Dart中的抽象类

Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口。

  1、抽象类通过abstract 关键字来定义

  2、Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法。

  3、如果子类继承抽象类,必须得实现里面的抽象方法

  4、如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法。

  5、抽象类不能被实例化,只有继承它的子类可以

extends抽象类 和 implements的区别:

  1、如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类

  2、如果只是把抽象类当做标准的话我们就用implements实现抽象类

案例:定义一个Animal 类要求它的子类必须包含eat方法

abstract class Animal{//使用abstract修饰的类,就是抽象类
  eat();   //抽象方法
 }

class Dog extends Animal{//当Dog类继承他的时候,若不重写Animal中的抽象方法,就会报错
  @override
  eat() {
     print('小狗在吃骨头');
  }
}

 如果抽象类中有多个抽象方法,子类都要全部实现。当然抽象类里也可以有普通方法。如:

abstract class Animal{

  eat();   //抽象方法
  run();  //抽象方法 

  printInfo(){
    print('我是一个抽象类里面的普通方法');
  }
}

class Dog extends Animal{
  @override
  eat() {
     print('小狗在吃骨头');
  }

  @override
  run() { 
    // TODO: implement run
    print('小狗在跑');
  } 
}

class Cat extends Animal{

  @override
  eat() {
    // TODO: implement eat
    print('小猫在吃老鼠');
  }

  @override
  run() {
    // TODO: implement run
    print('小猫在跑');
  }
}

main(){

  Dog d=new Dog();
  d.eat();
  d.printInfo();  

  Cat c=new Cat();
  c.eat();
  c.printInfo();

  // Animal a=new Animal();   //抽象类没法直接被实例化

}

Dart中多态

允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。

通俗的讲,多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。上面的继承也是多态的一种表现。

如何把子类的示例赋值给父类的引用?如下:

abstract class Animal{
  eat();   //抽象方法
}

class Dog extends Animal{
  @override
  eat() {
     print('小狗在吃骨头');
  }

  run(){                //子类中特有的方法
    print('run');
  }
}

class Cat extends Animal{

  @override
  eat() {  
    print('小猫在吃老鼠');
  }

  run(){                //子类中特有的方法
    print('run');
  }
}

main(){

  Animal d=new Dog();    //注意这里,用父类是声明这个变量。将子类实例化赋值给父类的变量
  d.eat();               //此时,就只能调用父类规定的方法,而不能调用子类独有的方法

  Animal c=new Cat();
  c.eat();
}

接口

和Java一样,dart也有接口,但是和Java还是有区别的。

首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。

同样使用implements关键字进行实现。

但是dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。

而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。

建议使用抽象类定义接口。

需求:定义一个DB库 支持 mysql  mssql  mongodb三个类里面都有同样的方法

abstract class Db{   //当做接口   接口:就是约定 、规范
    String uri;      //数据库的链接地址
    add(String data);
    save();
    delete();
}
//以上说明,实现Db借口,必须实现uri字符串,和add,save,delete方法

class Mysql implements Db{

  @override
  String uri;

  Mysql(this.uri);

  @override
  add(data) {
    // TODO: implement add
    print('这是mysql的add方法'+data);
  }

  @override
  delete() {
    // TODO: implement delete
    return null;
  }

  @override
  save() {
    // TODO: implement save
    return null;
  }

  remove(){
  }
}



class MsSql implements Db{

  @override
  String uri;

  @override
  add(String data) {
    print('这是mssql的add方法'+data);
  }

  @override
  delete() {
    // TODO: implement delete
    return null;
  }

  @override
  save() {
    // TODO: implement save
    return null;
  }

}

main() {
//操作这个数据库
  Mysql mysql=new Mysql('xxxxxx');
  mysql.add('1243214');   

}

接口 文件分离

可以参考前面 import的使用,新建一个文件,将代码粘进去就好了。这样的好处就是可以想用谁就引入谁。

import 'lib/MsSql.dart';//只需要通过import导入路径,就可以正常使用

main() {

  MsSql mssql=new MsSql();
  mssql.uri='127.0.0.1';
  mssql.add('增加的数据');
}

Dart中implements实现多个接口

首先定义两个接口,A和B

abstract class A{
  String name;
  printA();
}

abstract class B{
  printB();
}

class C implements A,B{ //可以使用implements实现多个接口,类名之间用,隔开
  @override
  String name;          //实现多个接口,就要实现多个接口中的所有方法
  @override
  printA() {
    print('printA');
  }

  @override
  printB() {
    // TODO: implement printB
    return null;
  }
}

void main(){
  C c=new C();
  c.printA();//
}

Dart中的mixins   with的使用

mixins的中文意思是混入,就是在类中混入其他功能。

在Dart中可以使用mixins实现类似多继承的功能

因为mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:

  1、作为mixins的类只能继承自Object,不能继承其他类

  2、作为mixins的类不能有构造函数

  3、一个类可以mixins多个mixins类

  4、mixins绝不是继承,也不是接口,而是一种全新的特性

示例代码:

class A {
  String info="this is A";
  void printA(){
    print("A");
  }
}

class B {
  void printB(){
    print("B");
  }
}

class C with A,B{    //在这里,使用with关键字来实现同时继承A和B的效果
                    //如果A类或者B类继承其他的类,则不能这样写

}

void main(){
  var c=new C(); 
  c.printA();        //可以看到,c可以调用A和B类中的方法
  c.printB();
  print(c.info);     //输出结果:this is A
}

 如果现在多了一个类Person,C想拥有A类,B类,和Person类的方法,可以这样写

class Person{
}

class A {
  String info="this is A";
  void printA(){
    print("A");
  }
}

class B { 
  void printB(){
    print("B");
  }
}

class C with Person,B,A{
  C(String name, num age) : super(name, age);
}
//或者:
class C extends Person with B,A{

}

若Person类中有默认构造函数,则只能使用第二种方法即:

class Person{
  String name;
  num age;
  Person(this.name,this.age);

  printInfo(){
    print('${this.name}----${this.age}');
  }
  void run(){
    print("Person Run");
  }
}

class A {
  String info="this is A";
  void printA(){
    print("A");
  }
  void run(){
    print("A Run");
  }
}

class B { 
  void printB(){
    print("B");
  }

  void run(){
    print("B Run");
  }
}

class C extends Person with B,A{
  C(String name, num age) : super(name, age);
}

void main(){ 

var c = C('张三',20);

print(c.info);
   c.run();//输出结果:A Run
}

注意:C类继承的三个类中,都有run()方法,而最后的输出结果是A Run,说明若父类里有同名的方法,在使用是,后面继承的类会覆盖前面类中的方法。

mixins的实例类型是什么?

很简单,mixins的类型就是其超类的子类型。

void main(){ 
  var c=new C(); 
  print(c is C);    //true
  print(c is A);    //true
  print(c is B);   //true
}

Dart中的泛型

通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

比如我们想传入什么类型,就返回什么类型,以往写法:

1.只能返回string类型的数据

String getD ata(String value){
      return value;
  }

2.同时支持返回 string类型 和int类型 ,但是代码冗余

   String getData1(String value){
       return value;
   }

   int getData2(int value){
       return value;
   }

3.同时返回 string类型 和number类型 ,不指定类型可以解决这个问题

   getData(value){
     return value;
   }

 但是不指定类型放弃了类型检查。我们现在想实现的是传入什么 返回什么。

这时候就可以把这个方法定义成一个泛型方法

泛型方法

方法的定义:

 T getData<T>(T value){
       return value;
   }

方法的使用:

  T getData<T>(T value){
      return value;
  }

void main(){
     print(getData(21));
     print(getData('xxx'));    //这样写,可以正常打印,但是依然没有类型校验
                           
    //所以在使用泛型方法的时候,可以在调用方法的时候给他指定类型
    getData<String>('你好');   //<>内传入要指定的类型
    print(getData<int>(12));
}

 泛型类

集合List 就是一个泛型类,用法如下:

 

 //正常定义一个list,可以添加任意类型的元素
  List list=new List();
  list.add(12);
  list.add("你好");
  print(list); //输出结果:12,你好

  //规定了泛型的List
  List list1=new List<String>();
  //list1.add(12);  //此时,这里就报错了,因为12是一个int
  list1.add("你好");//只能输入String类型的元素
  
 //同理,只能增加int型数据的List
   List list2=new List<int>();
   //list2.add("你好");  //错误写法
   list2.add(12);

自定义一个泛型类

案例:把下面类转换成泛型类,要求List里面可以增加int类型的数据,也可以增加String类型的数据。但是每次调用增加的类型要统一

class PrintClass<T>{

      List list=new List<T>();
      void add(T value){
          this.list.add(value);
      }

      void printInfo(){         
          for(var i=0;i<this.list.length;i++){
            print(this.list[i]);
          }
      }
 }

这样就定义好了一个泛型类,只需要在普通类后面加上<T>,类里需要相同数据类型的地方,都用<T>表示。在调用的时候,声明要传入的类型:

main() { 
  //若在初始化的时候,不声明类型,则依然没有数据校验
  PrintClass p=new PrintClass();
  p.add(11);
  p.add('xxx');
  p.printInfo();

  PrintClass p1=new PrintClass<String>();//相当于把这个string赋值给了T
  p1.add('你好');
  p1.add('哈哈');
  p1.printInfo();

  PrintClass p2=new PrintClass<int>();
  p2.add(12);
  p2.add(23);
  p2.printInfo();
}

泛型接口

Dart中的泛型接口:

    实现数据缓存的功能:有文件缓存、和内存缓存。内存缓存和文件缓存按照接口约束实现。

    1、定义一个泛型接口 约束实现它的子类必须有getByKey(key) 和 setByKey(key,value)

    2、要求setByKey的时候的value的类型和实例化子类的时候指定的类型一致

因为在drat中接口可以是普通类,也可以是抽象类,所以接口的定义和类的定义类似:

abstract class Cache<T>{
  getByKey(String key);
  void setByKey(String key, T value);
}
//这样,就定义好了一个泛型的接口

class FlieCache<T> implements Cache<T>{    //注意,由于接口是泛型的,所以子类也要是泛型

  @override
  getByKey(String key) {   
    return null;
  }

  @override
  void setByKey(String key, T value) {
   print("我是文件缓存 把key=${key}  value=${value}的数据写入到了文件中");
  }

}



class MemoryCache<T> implements Cache<T>{
  @override
  getByKey(String key) {  
    return null;
  }

  @override
  void setByKey(String key, T value) {
       print("我是内存缓存 把key=${key}  value=${value} -写入到了内存中");
  }
}

void main(){

     MemoryCache m=new MemoryCache<String>();//指定String类型的Value
     m.setByKey('index', '首页数据'); 
 
     MemoryCache m=new MemoryCache<Map>();//指定Map类型的Value
     m.setByKey('index', {"name":"张三","age":20});:
}

Dart中的库 自定义库、系统库、第三方库

Dart中的库

前面介绍Dart基础知识的时候基本上都是在一个文件里面编写Dart代码的,但实际开发中不可能这么写,模块化很重要,所以这就需要使用到库的概念。在Dart中,库的使用时通过import关键字引入的。

library指令可以创建一个库,每个Dart文件都是一个库,即使没有使用library指令来指定。

Dart中的库主要有三种:

    1、我们自定义的库    

          import 'lib/xxx.dart';

    2、系统内置库       

          import 'dart:math';   

          import 'dart:io';

          import 'dart:convert';

很多,以后用到哪个,查哪个就行

    3、Pub包管理系统中的库 

        https://pub.dev/packages

        https://pub.flutter-io.cn/packages

        https://pub.dartlang.org/flutter/

        1、需要在自己想项目根目录新建一个pubspec.yaml

        2、在pubspec.yaml文件 然后配置名称 、描述、依赖等信息

        3、然后运行 pub get 获取包下载到本地 

        4、项目中引入库 import 'package:http/http.dart' as http; 看文档使用

 Dart中导入自己本地库

import 'lib/Animal.dart';
main(){
  var a=new Animal('小黑狗', 20);
  print(a.getName());
}

导入系统内置库 math库 

import 'dart:io';
import "dart:math"; //引入系统自带的库,math库

main(){
    print(min(12,23));//求两个数的最小数
    print(max(12,25));//求两个数的最大数
}

导入系统内置库实现请求数据httpClient

import 'dart:io';
import 'dart:convert';//用于转化UTF8格式

void main() async{ 

  var result = await getDataFromZhihuAPI();//await作用:等待异步完成
  print(result);

}

//api接口: http://news-at.zhihu.com/api/3/stories/latest
getDataFromZhihuAPI() async{ //这是一个异步的方法,所以调用时,main函数也得是异步的

  //1、创建HttpClient对象
  var httpClient = new HttpClient(); 

  //2、创建Uri对象
  var uri = new Uri.http('news-at.zhihu.com','/api/3/stories/latest');

  //3、发起请求,等待请求
  var request = await httpClient.getUrl(uri);

  //4、关闭请求,等待响应
  var response = await request.close();

  //5、解码响应的内容
  return await response.transform(utf8.decoder).join();

}

关于 Async Await

async和await

  这两个关键字的使用只需要记住两点:

    只有async方法才能使用await关键字调用方法

    如果调用别的async方法必须使用await关键字

async是让方法变成异步。

await是等待异步方法执行完成。

举个例子:

void main() async{
  var result = await testAsync(); //因为testAsync是异步的,所以要用await获取
  print(result);
}

//这样就定义了一个异步方法
testAsync() async{
  return 'Hello async';
}

Dart 导入Pub包管理系统中的库

即引入第三方的包

1、从下面网址找到要用的库

        https://pub.dev/packages

        https://pub.flutter-io.cn/packages

        https://pub.dartlang.org/flutter/

2、在根目录下创建一个pubspec.yaml文件,内容如下

    name: xxx//定义好名称,建议英文

    description: A new flutter module project.

    dependencies:   //配置依赖

        http: ^0.12.0+2

        date_format: ^1.0.6

3、配置dependencies

4、运行pub get 获取远程库

5、看文档引入库使用

使用第三方库http.dart和date_format.dart示例:

import 'dart:convert' as convert;
import 'package:http/http.dart' as http;
import 'package:date_format/date_format.dart';

main() async {

    var url = "http://http://news-at.zhihu.com/api/3/stories/latest";

    Await the http get response, then decode the json-formatted responce.

    var response = await http.get(url);
     
    if (response.statusCode == 200) {
        var jsonResponse = convert.jsonDecode(response.body);
        print(jsonResponse);
    } else {

        print("Request failed with status: ${response.statusCode}.");
     }

    print(formatDate(DateTime(1989, 2, 21), [yyyy, '*', mm, '*', dd]));
}

Dart库的重命名  Dart冲突解决

冲突解决

当引入两个库中有相同名称标识符的时候,如果是java通常我们通过写上完整的包名路径来指定使用的具体标识符,甚至不用import都可以,但是Dart里面是必须import的。当冲突的时候,可以使用as关键字来指定库的前缀。如下例子所示:

引入的两个库Person1.dart,Person2.dart中有同名的方法Person(),直接初始化,系统会不知道要调用哪一个,这时这样写就会报错:

import 'lib/Person1.dart';
import 'lib/Person2.dart';

main(List<String> args) {
  Person p1=new Person('张三', 20);
  p1.printInfo();
}

这时就需用as关键字来指定库的前缀

import 'lib/Person1.dart';
import 'lib/Person2.dart' as lib; //将Person2重命名为lib

main(List<String> args) {
  Person p1=new Person('张三', 20);
  p1.printInfo();//输出结果:Person1:张三 ---20

  lib.Person p2=new lib.Person('李四', 20);//这时调用的就是Person2的内容
  p2.printInfo();//输出结果:Person2:李四 ---20
}

库的部分导入

  如果只需要导入库的一部分,有两种模式:

     模式一:只导入需要的部分,使用show关键字,如下例子所示:

      import 'package:lib1/lib1.dart' show foo;

     模式二:隐藏不需要的部分,使用hide关键字,如下例子所示:

      import 'package:lib2/lib2.dart' hide foo;     

import 'lib/myMath.dart' show getAge;//只引入myMath库里的getAge()方法
import 'lib/myMath.dart' hide getName;//不引入myMath库里的getName()方法

 延迟加载

    也称为懒加载,可以在需要的时候再进行加载。

    懒加载的最大好处是可以减少APP的启动时间。

    懒加载使用deferred as关键字来指定,如下例子所示:

    import 'package:deferred/hello.dart' deferred as hello;

    当需要使用的时候,需要使用loadLibrary()方法来加载:

    greet() async {
      await hello.loadLibrary();
      hello.printGreeting();
    }

 

 

 

上一篇:Dart基础学习总结(中)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值