• Dart:补充


    前言

    前面那几篇Dart文章,写的很基础,是我初学时根据教程简单记录的。这篇文章主要用来对前面内容进行补充,会随着学习不断扩展。

    特殊运算符

    ??=

    ??= 是空值赋值运算符,当变量是空值时才会进行赋值操作

    示例

      var b = null;
      b ??= 2;
      print("b可能为空值,b的值是${b}"); //2
    
    • 1
    • 2
    • 3

    注: 这里的空值指的是null

    ??

    ?? 可以理解为三元运算符的简写

    示例

      var a = null;
      var b = a ?? 'aaa';
      print(b); // aaa
    
      //等价于
      var c = a != null ? a : 'aaa';
      print(c); // aaa
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注: 不要跟js混了,js中直接会对null进行类型转换

    ..

    .. 是级联运算符

    示例

    main() {
      var p1 = Person();
      p1.name = 'p1';
      p1.run();
    
      //等价于
      var p2 = Person()
        ..name = 'p2'
        ..run();
    }
    
    class Person {
      String name = '';
    
      run() {
        print("${this.name}正在跑!");
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    循环

    for in

    main() {
      List<String> nameList = ['张三', '李四'];
    
      for (var name in nameList) {
        print(name);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    dynamic、var、object 三种类型的区别

    dynamic 表示是动态的,数据类型是指任意类型。通过它定义的变量编译时会关闭类型检查,这会导致运行时有可能会出错。在开发中不要直接使用它

    var 可以理解为我不关心这个变量是什么类型,编译时系统会自动进行推断。

    object:是Dart 对象的基类,当你定义: object a = 123;时这个时候系统会认为a是个对象,你可以调用a的toString()和hashCode()方法,因为Object 提供了这些方法,但是如果你尝试调用a的substring方法时,静态类型检查会运行报错。

    初始化列表

    一般在使用可选参数时会用到,例如下面的代码,age是可选参数,虽然在类中已经初始化了age,但是这样是不允许的。
    在这里插入图片描述

    正确写法
    在这里插入图片描述
    最开始是这样的

     Person(this.name, {int age}) : this.age = age ?? 10 {}
    
    • 1

    但是一直提示错误,后来才想起来 dart 2.17版本使用可选参数时要么一开始就赋值,比如 {int age = 10} ,要么就加一个问号 {int? age}

    构造函数重定向

    main() {
      var p1 = Person("p1");
      print(p1.age); //0
    }
    
    class Person {
      String name;
      int age;
    
    //构造函数重定向
      Person(String name) : this._internal(name, 0);
    
      Person._internal(this.name, this.age);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    常量构造函数

    常量构造函数可以保证创建出来的对象是一个(构造函数的值必须是一样的)

    普通构造函数

    main() {
      var p1 = Person("a");
      var p2 = Person('a');
    
      var result = identical(p1, p2);
    
      print("p1和p2对应的对象是一个:${result}"); //false
    }
    
    class Person {
      String name;
      Person(this.name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    常量构造函数

    main() {
      const p1 = Person("a");
      const p2 = Person('a');
    
      var result = identical(p1, p2);
    
      print("p1和p2对应的对象是一个:${result}"); //true
    }
    
    class Person {
      final String name;
      const Person(this.name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意点:
    1、如果是普通构造函数,那么 const p1 = Person("a"); 是错误的,会提示构造函数不是常量构造函数;
    如果是常量构造函数,那么 const p1 = Person("a");var p1 = Person("a"); 都是可以的,但是只有都是用const 定义的对象,其 对象才指向同一个内存。
    `
    2、类中只能有一个常量构造函数

    3、构造函数如果是常量构造函数,那么类中不允许出现变量
    在这里插入图片描述

    工厂构造函数

    dart中用factory 修饰的构造函数是工厂构造函数。图片构造函数会默认返回创建的对象,而工厂构造函数,需要手动通过return 返回创建的对象。

    示例:

    /// 工厂构造函数,
    /// 也叫 “单例模式”,是设计模式的一种,是面向对象很重要的一种设计模式,
    /// 一个程序无论实例化多少类,工厂构造函数只返回第一次实例化的对象,这样
    /// 就会节约许多计算机资源。普通构造函数每次实例化类的时候,就会开辟一段
    /// 内存来存放实例化对象资源。
    class Person {
      String name;
    
      // 静态属性存放实例化对象
      static var instance;
    
      //工厂构造函数
      factory Person([String name = "刘备"]) {
        // 工厂构造函数不能使用 this 关键字
        Person.instance ??= new Person.newSelf(name);
        return Person.instance;
      }
    
      Person.newSelf(this.name);
    }
    
    void main() {
      var p1 = new Person('关羽');
      print(p1.name);
    
      var p2 = new Person('张飞');
      print(p2.name);
    
      var p3 = new Person('诸葛亮');
      print(p3.name);
    
      // 判断两次实例化的对象是否一致。
      print(p1 == p2);
      print(p1 == p3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    抽象类的实例化

    参考:Dart - 抽象类的实例化 ,这篇文章讲的很清楚可以看一下。
    虽然前面说了抽象类不能够进行实例化,但是抽象类可以借助工厂函数来实现抽象化。典型的例子就是Map,进入到Map 我们可以看到

    void main() {
      var a = Map();
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    原因就是:工厂方法可以返回一个实例对象,但这个对象的类型不一定就是当前类
    打印一下Map对象的运行时类型,可以看到是 _InternalLinkedHashMap
    在这里插入图片描述

    external 和 @patch

    external 可以分离方法的声明与实现
    @patch 关联某个类中用 external 修饰的方法的实现
    
    • 1
    • 2

    示例

    void main() {
      var a = Animal();
    
      print(a.runtimeType);
    }
    
    abstract class Animal {
      void eat();
    
      void sleep() {
        print("睡觉");
      }
    
      factory Animal() {
        return Cat();
      }
    }
    
    class Cat implements Animal {
      void eat() {
        print("吃");
      }
    
      void sleep() {
        print('睡');
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注: 只能使用 implements ,不能使用 extends。在抽象类中定义了工厂构造方法后,在子类中不能定义除工厂构造方法外的其它构造方法了,会报错。
    在这里插入图片描述

    好处: 复用同一套API的声明,可以针对不同的平台做不同的实现

    utils.dart

    int sum(int a, int b) {
      return a + b;
    }
    
    int multiply(int a, int b) {
      return a * b;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    库的重命名

    当我们导入库中的某个方法和当前文件中的某个方法重名时,我们可以通过 as 来起个别名。
    例如:

    import './utils.dart' as Utils;
    
    void main() {
      print(Utils.sum(1, 2));
    }
    
    void sum(int a, int b) {
      print(a + b);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    show 和 hide

    默认情况下导入一个库时,会导入所有的公共属性和公共方法。但是可以通过 showhide 来实现只导入部分内容。

    show: 执行要导入的内容
    hide: 隐藏要导入的内容,导入其他未隐藏的内容。

    //只导入sum
    import './utils.dart' as Utils show sum;
    
    • 1
    • 2

    在这里插入图片描述

    //导入除sum以外的其他内容
    import './utils.dart' as Utils hide sum;
    
    • 1
    • 2

    在这里插入图片描述

    导入多个工具类

    这个跟node.js 非常类似,就是定义一个公共入库文件,比如 index.dart ,在该文件中导出其他类

    export 'utils.dart';
    
    • 1

    使用时只需要导入 index.dart

  • 相关阅读:
    MySQL数据类型:字符串类型详解
    2023.10.02
    组合式API_生命周期
    MySQL事务 MVCC的实现原理
    安卓开发基础知识-补习9
    Tomcat
    java连接zookeeper
    springboot快速搭建ftpserver服务端
    【数据结构】堆排序和Top-k问题
    在键盘输入一个数输出的是该数二进制的个数--c语言
  • 原文地址:https://blog.csdn.net/weixin_41897680/article/details/125753378