Dart 编程语言不详细学习指北


本文章是博主在此网站学习 Dart 语言时所摘录的一些重要内容,用于快速掌握 Dart 语言,详细完整内容请点击原网页。

重要的概念

  • Dart 万物皆对象,并且所有的对象都是对应一个 的实例。

  • 尽管 Dart 是强类型的,但是 Dart 可以推断类型,所以类型注释是可选的。

  • Dart 支持顶级函数(例如 main() ), 同样函数绑定在类或对象上(分别是 静态函数实例函数 )。 以及支持函数内创建函数 ( 嵌套局部函数 ) 。

  • 类似地, Dart 支持顶级变量 , 同样变量绑定在类或对象上(静态变量和实例变量)。 实例变量有时称为字段或属性。

  • Dart 没有关键字 “public” , “protected” 和 “private” 。 如果标识符以下划线(_)开头,则它相对于库是私有的。

变量和常量

如果对象不限定为单个类型,可以指定为 对象类型动态类型

dynamic name = 'Mahoo12138';

未初始化的变量默认值是 null。即使变量是数字类型默认值也是 null,因为在 Dart 中一切都是对象,数字类型也不例外:

int lineCount;
assert(lineCount == null);

在生产环境代码中 assert() 函数会被忽略,不会被调用。 在开发过程中, assert(condition) 会在非 true 的条件下抛出异常

Final 变量的值只能被设置一次; Const 变量在编译时就已经固定 (Const 变量是隐式 Final 的类型),常量如果是类级别的,请使用 static const

类与函数

  • Dart 使用 class 关键字表示一个类,对象具有由函数和数据(分别为方法和实例变量)组成的成员,未初始化实例变量的默认人值为 “null”。

  • 构造函数的名称可以是类名 ClassName 或者类名和标识符 ClassName.identifier 。 其中构造函数名称是“ClassName”的函数叫类名构造函数;构造函数名称是“ClassName.identifier”的函数叫命名构造函数

  • 默认构造函数——在没有声明构造函数的情况下, Dart 会提供一个默认的构造函数。 默认构造函数没有参数并会调用父类的无参构造函数。

构造函数不被继承

子类不会继承父类的构造函数。 子类不声明构造函数,那么它就只有默认构造函数 (匿名,没有参数) :

class Point {
  num x, y;

  Point(num x, num y) {
    this.x = x;
    this.y = y;
  }
  // 语法糖
  Point(this.x, this.y);
  // 命名构造函数  
  Point.origin() {
    x = 0;
    y = 0;
  }
}

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
var p3 = Point.origin();

调用父类非默认构造函数

默认情况下,子类的构造函数会自动调用父类的默认构造函数(未命名,无参数),如果父类中没有匿名无参的构造函数, 则需要手工调用父类的其他构造函数。 在当前构造函数冒号 (:) 之后,函数体之前,声明调用父类构造函数:

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person 没有默认构造函数
  // 必须使用 super.fromJson(data).调用父类的命名构造函数
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

void main() {
  var emp = new Employee.fromJson({});
  // 输出
  // in Person
  // in Employee
}

构造函数的调用顺序

  • 子类的构造函数中执行的操作顺序如下:

    1. 初始化列表

    2. 父类的无参构造函数

    3. 本类的无参构造函数

      void main() {
      var result = new TestChild.area(3, 4);
      print('面积为:${result.area}');
      // Print:
      // Test 空参构造
      // TestChild 有参构造
      // 面积为:6.0
      }
      
      class Test {
      num width;
      num height;
      num area;
      
      // 必须加上空参构造,如果注释掉 它的子类会报错
      Test() {
       print('Test 空参构造');
      }
      
      Test.area(width, height)
         : width = width,
           height = height,
           area = width * height {
       print('Test 有参构造');
      }
      }
      
      class TestChild extends Test {
      
      num width;
      num height;
      num area;
      
      TestChild() {
       print('TestChild 空参构造');
      }
      
      TestChild.area(num width, num height)
       : area = (width * height)/2 {
       print('TestChild 有参构造');
      }
      }

重定向构造函数

  • 有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。重定向构造函数的主体是空的,构造函数调用出现在冒号:之后:

      void main() {
        var result = new Test(4, true, '数字', 10);
        var result1 = new Test.test1(4, true);
        var result2 = new Test.test2(1,false,'mahoo')
    
      }
    
      class Test {
        num a;
        bool b;
        String c;
        num d;
        // 主构造函数
        Test(this.a, this.b, this.c, this.d);
    
        // 委托给主构造函数
        Test.test1(num x,bool y) : this(x, y,'', 0);
        Test.test2(num a,bool b, String c) : this(a, b, c, 0);
        Test.test3(num a,bool b, String c,num d) : this(a, b, c, d);
      }
  • 要在运行时获取对象的类型,可以使用Object类的 runtimeType 属性,该属性返回一个Type对象

      var a = 10;
      print('a 的类型是: ${a.runtimeType}'); // a 的类型是: int
  • Dart和Java一样,使用 extends 关键字,表示一个类继承另一个类。

  • 使用static关键字修饰的类范围的变量。静态变量(类变量)对于类范围的状态和常量很有用。静态变量在使用之前不会初始化。

  • 使用 abstract 修饰符定义抽象类(无法实例化的类)。抽象类对于定义接口非常有用,通常还有一些实现。如果希望抽象类看起来是可实例化的,请定义工厂构造函数。

工厂构造函数

当执行构造函数并不总是创建这个类的一个新实例时,则使用 factory 关键字。 例如,一个工厂构造函数可能会返回一个 cache 中的实例, 或者可能返回一个子类的实例。

工厂构造函数是通过代码来决定返回的实例对象;工厂构造函数类似于 static 静态成员,无法访问 this 指针;一般需要依赖其他类型构造函数:

class People {
  String name;
  int age, sex;
  static People _cache;

  People() {
    print('Dart --> People()');
  }

  People.fromMap(map) {
    this.name = map['name'];
    this.age = map['age'];
    this.sex = map['sex'];
    print('Dart --> People.fromMap($map) --> $name, $age, $sex');
  }

  factory People.map(map) {
    // 当不存在缓存的实例 People 时则创建并返回
    if (People._cache == null) {
      People._cache = new People.fromMap(map);
      print('Dart --> People.map($map) --> ${map['name']}, ${map['age']}, ${map['sex']} --> People._cache == null');
    }
    print('Dart --> People.map($map) --> ${map['name']}, ${map['age']}, ${map['sex']}');
    return People._cache;
  }

  factory People.fromJson(json) => People();
}

void main() {
  Map map = {'name': 'Mahoo12138', 'age': 20, 'sex': 0};
  People people = People.map(map);
  print('People.name=${people.name}, age=${people.age}, sex=${people.sex}, hashCode=${people.hashCode}');
  // 输出中,people 和 people2 的 hashcode 是相同的
  People people2 = People.map(map);
  print('People2.name=${people2.name}, age=${people2.age}, sex=${people2.sex}, hashCode=${people2.hashCode}');

  People people3 = People.fromMap(map);
  print('People3.name=${people3.name}, age=${people3.age}, sex=${people3.sex}, hashCode=${people3.hashCode}');

  People people4 = People.fromJson(map);
  print('People4.name=${people4.name}, age=${people4.age}, sex=${people4.sex}, hashCode=${people4.hashCode}');
}

工厂构造函数还可以实现单例:

class Singleton {
  static final Singleton _singleton = Singleton.internal();
  // 工厂构造函数
  factory Singleton() => _singleton;
  // 命名构造函数
  Singleton.internal();
}

Typedef

目前,typedef 只能使用在函数类型上,对函数类型的对象做一个别名,例如:

typedef Compare = int Function(Object a, Object b);

void main() {
  int fun(Object a, Object b) => 0;
  assert(fun is Compare);
}

int Function(Object a, Object b);为一个函数类型的对象的类型信息。


文章作者: Mahoo Huang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mahoo Huang !
评论
 上一篇
Vuejs 移动端开发初始配置 Vuejs 移动端开发初始配置
添加 viewpoit<meta>标签内添加viewpoit,以此来动态的获取用户设备的屏幕宽度和不允许用户手动放大和缩小页面等 清除初始样式 & document.querySelectorAll('.
2020-11-13
下一篇 
STM32F1XX驱动温度检测模块DS18B20 STM32F1XX驱动温度检测模块DS18B20
DS18B20 单线总线的工作方式1. DS18B20 简介DS18B20单线数字温度传感器,即“一线器件”,其具有如下独特的优点。 采用单线总线的接口方式。与微处理器连接时,仅需要1条口线即可实现微处理器与 DS18B20 的双向通信。
2020-10-13
  目录