Dart语言基础,看完这篇文章就够了(二)

Dart

文章内容是我在学习Flutter过程中对知识点的梳理和总结。如有不对的地方,欢迎指出。

本文承接Dart语言基础,看完这篇文章就够了(一),进一步了解Dart语法知识。

1 流程控制语句

  • if else
  • for, forEach, for-in
  • while , do-whild
  • break,continue
  • switch case
 var collection = [0, 1, 2];
 
  //forEach
  collection.forEach((item) => print('forEach: $item'));
  
  //for-in遍历元素
  for (var item in collection) {
    print('for-in: $item');
  }

2 异常

  • Dart 提供了 Exception 和 Error 类型, 以及一些子类型。还可以定义自己的异常类型。但是,Dart 代码可以抛出任何非 null 对象为异常,不仅仅是实现了 Exception 或者 Error 的对象。

2.1 异常-类型

  1. Exception类型
    Exception
  2. Error类型
    Error

2.2 异常-抛出 throw

  1. 所有的 Dart 异常是非检查异常。 方法不一定声明了他们所抛出的异常, 并且你不要求捕获任何异常。
  2. Dart 代码可以抛出任何非 null 对象为异常,不仅仅是实现了 Exception 或者 Error 的对象。
// 抛出Exception 对象
// throw new FormatException(‘格式异常');

// 抛出Error 对象
// throw new OutOfMemoryError();

// 抛出任意非null对象
// throw '这是一个异常';

2.3 异常-捕获 try catch

  1. 可以使用on 或者 catch 来声明捕获语句,也可以 同时使用。使用 on 来指定异常类型,使用 catch 来 捕获异常对象。
  2. catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为堆栈信息 (一个 StackTrace 对象)。
  3. 可以使用rethrow把捕获的异常重新抛出。
  try {
    throw new NullThrownError();
//    throw new OutOfMemoryError();
  } on OutOfMemoryError {
    //on 指定异常类型
    print('没有内存了');
//    rethrow; //把捕获的异常给 重新抛出
  } on Error {
    //捕获Error类型
    print('Unknown error catched');
  } on Exception catch (e) {
    //捕获Exception类型
    print('Unknown exception catched');
  } catch (e, s) {
    //catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为StackTrace对象堆栈信息
    print(e);
    print(s);
  }
}

3 类

3.1 普通构造函数

Java中写法

class Point {
  double x;
  double y;

  Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
}

Dart建议写法

class Point {
  num x;
  num y;
  Point(this.x, this.y);
}
var p = new Point(1, 1); //new 可省略 var point = Point(1, 2);
print(p.x);
//  Point p1;
//  print(p1.runtimeType); //可以使用Object类的runtimeType属性,获取对象的类型

3.2 命名构造函数

  • 使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图。
class Point {
  int x;
  int y;

  Point(this.x, this.y);
  //命名构造函数
  Point.mingMing(Map map) {
    this.x = map['x'];
    this.y = map['y'];
  }

}

调用如下:

p = Point.mingMing({'x': 2, 'y': 2});
print(p.x);

3.3 重定向构造函数

  • 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
  int x;
  int y;

  Point(this.x, this.y);

  Point.mingMing(Map map) {
    this.x = map['x'];
    this.y = map['y'];
  }
  
  //重定向构造函数
  Point.chongDingXiang(num x) : this(x, 0);
}

调用如下:

var p = Point.chongDingXiang(3);
print(p.x);

3.4 初始化列表

  1. 在构造函数体执行之前可以初始化实例参数。 使用逗号分隔初始化表达式。
  2. 初始化列表非常适合用来设置 final 变量的值。
import 'dart:math';

class Point {
  //final变量不能被修改,必须被构造函数初始化
  final num x;
  final num y;
  final num distanceFromOrigin;

  //初始化列表
  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

3.5 调用超类构造函数

  1. 超类命名构造函数不会传递,如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数;
  2. 如果超类没有默认构造函数, 则你需要手动的调用超类的其他构造函数;
  3. 调用超类构造函数的参数无法访问 this。
  4. 在构造函数的初始化列表中使用 super(),需要把它放到最后。
class Parent {
  int x;
  int y;

  Parent.f(x, y)
      : x = x,
        y = y {
    print("父类命名构造函数");
  }
}

class Child extends Parent {
  int x;
  int y;

  Child(x, y)
      : x = x,
        y = y,
        super.f(x, y) {
    print('子类默认构造函数');
  }

  Child.f(x, y)
      : x = x,
        y = y,
        super.f(x, y) {
    print("子类命名构造函数");
  }
}

调用:

  var c = Child(1, 2);
  print(c);

运行结果:
运行结果

3.6 常量构造函数

  1. 定义const构造函数要确保所有实例变量都是final。
  2. const关键字放在构造函数名称之前。
class Point2 {
  //定义const构造函数要确保所有实例变量都是final
  final num x;
  final num y;
  static final Point2 origin = const Point2(0, 0);

  //const关键字放在构造函数名称之前,且不能有函数体
  const Point2(this.x, this.y);
}

调用:

  Point2 p =const Point2(1, 2);
  var p2 =const Point2(1, 2);
  print(identical(p, p2));

输出结果:true

3.7 工厂构造函数

  1. 工厂构造函数是一种构造函数,与普通构造函数不同,工厂函数不会自动生成实例,而是通过代码来决定返回的实例对象。
  2. 如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义这个构造函数。
  3. 工厂构造函数无法访问this。
class Singleton{
  String name;
  //工厂构造函数无法访问this,所以这里要用static
  static Singleton _cache;

  //工厂方法构造函数,关键字factory
//  factory Singleton({String name = 'name'}){
//    if(Singleton._cache == null){
//      Singleton._cache = Singleton._newObject(name);
//    }
//    return Singleton._cache;
//  }
  //注释内容简写
  factory Singleton([String name = 'name']) =>Singleton._cache ??=Singleton._newObject(name);
  //定义一个命名构造函数用来生产实例
  Singleton._newObject(this.name);
}

调用:

var s = Singleton('555');
var s2 = Singleton('666');
print(identical(s, s2));

运行结果:true

3.7 Setter和Getter

class Rectangle {
  num left;
  num top;
  num width;
  num height;

  Rectangle(this.left, this.top, this.width, this.height);

  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

调用:

  var rect = new Rectangle(1, 1, 10, 10);
  print(rect.left);
  rect.right = 12; //调用set
  print(rect.left);//调用get

3.8 抽象类

  1. 不能被实例化,除非定义一个工厂构造函数。
  2. 抽象类通常用来定义接口, 以及部分实现。
  3. 抽象类通常具有抽象方法,抽象方法不需要关键字,以分号结束即可。
  4. 接口方式使用时,需要重写抽象类的成员变量和方法,包括私有的。
  5. 一个类可以implement一个普通类。Dart任何一个类都是接口。
  6. 一个类可以implement多个接口。

两种实现方式:

  • 工厂模式implement示例如下:
void main() {
  var footM = new Massage("foot");
  var backM = new Massage("back");
  var specialM = new Massage("special");
  footM.doMassage();
  backM.doMassage();
  specialM.doMassage();
}

abstract class Massage {
	//工厂模式
  factory Massage(String type) {
    switch (type) {
      case "foot":
        return FootM();
      case "back":
        return BackM();
      case "special":
        return specialM();
    }
  }

  void doMassage();
}

class FootM implements Massage {
  @override
  void doMassage() {
    print("FootM ---- doMassage()");
  }
}

class BackM implements Massage {
  @override
  void doMassage() {
    print("BackM ---- doMassage()");
  }
}

class specialM implements Massage {
  @override
  void doMassage() {
    print("specialM ---- doMassage()");
  }
}
  • 顶级函数extends示例如下:
void main() {
  var footM = massageFactory("foot");
  footM.doMassage();
}
//顶级函数
Massage massageFactory(String type) {
  switch (type) {
    case "foot":
      return FootM();
    case "back":
      return BackM();
    case "special":
      return specialM();
  }
}
//抽象类
abstract class Massage {
  void doMassage() {
    print("Massage");
  }
}

class FootM extends Massage {
  @override
  void doMassage() {
    print("FootM ---- doMassage()");
  }
}

class BackM extends Massage {
  @override
  void doMassage() {
    print("BackM ---- doMassage()");
  }
}

class specialM extends Massage {
  @override
  void doMassage() {
    print("specialM ---- doMassage()");
  }
}

3.9 可调用类

实现call() 方法可以让类像函数一样能够被调用。

void main(){
  var cf = new ClassFunction();
  var out = cf("tutou","flutter","laowang");
  print('$out');
  print(cf.runtimeType);
  print(out.runtimeType);
  print(cf is Function);
}
class ClassFunction {
  call(String a, String b, String c) => '$a $b $c!';
}

运行结果:
运行结果

3.10 重载操作符

  • 关键字operator

示例如下:

void main() {
  var p1 = Person("小王", 18, 170);
  var p2 = Person("老王", 28, 180);
  if (p2 > p1) {
    print("老王比小王年龄大");
  }
  if (p1 < p2) {
    print("老王比小王高");
  }

  print('老王比小王大${p2 - p1}岁');
  print("老王和小王的年龄和${p1 + p2}");
}

class Person {
  String name;
  int age;
  int height;

  Person(this.name, this.age, this.height);

  bool operator >(Person p) {
    return this.age > p.age;
  }

  bool operator <(Person p) {
    return this.height < p.height;
  }

  int operator +(Person p) {
    return this.age + p.age;
  }

  int operator -(Person p) {
    return this.age - p.age;
  }
}

运行结果如下:
运行结果

4 Mixin

关键字: with

  • 顺序问题
    1.如果2个或多个超类拥有相同签名的A方法,那么子类会以继承的最后一个超类中的A方法为准;
    2.当然这是子类没有重写A方法的前提下,如果子类自己重写了A方法则以本身的A方法为准;

示例如下:

void main() {
  print(AB().getMessage());
  print(BA().getMessage());
  print(C().getMessage());
  print(CC().getMessage());
}

class A {
  String getMessage() => 'A';
}

class B {
  String getMessage() => 'B';
}

class P {
  String getMessage() => 'P';
}

class AB extends P with A, B {}

class BA extends P with B, A {}

class C extends P with B, A {
  String getMessage() => 'C'; //优先级最高的是在具体类中的方法。
}

class CC extends P with B implements A {
} //这里的implement只是表明要实现A的方法,这个时候具体实现是再B中mixin了具体实现

运行结果:
运行结果

5 泛型

  1. Dart1.21开始可以使用泛型函数。
  2. 泛型函数可以在以下几个地方使用类型参数:
    ①函数的返回值类型;
    ②参数的类型;
    ③局部变量的类型;

5.1 泛型-与java区别

  • Java中的泛型信息是编译时的,泛型信息在运行时是不存在的;
  • Dart的泛型类型是固化的,在运行时也有可以判断的具体类型;
    示例如下:
var names = List<String>();
print(names is List<String>);//true
print(names.runtimeType); // List<String> 

注:在Java中,可以测试对象是否为List,但无法测试它是否是List<String>。

5.2 使用泛型,很多的容器对象,在创建对象时都可以定义泛型类型,跟java一样

  var list = List<String>();
  list.add('aaa');
  list.add('bbb');
  list.add('ccc');
  print(list);

  var map = Map<int, String>();
  map[1] = 'aaaa';
  map[2] = 'bbbb';
  map[3] = 'cccc';
  print(map);

5.3 泛型函数

void main() {
  V addCache<K, V>(K key, V value) {
    V temp = value;
    print('key:$key--------------value:$value');
    return temp;
  }
  var v = addCache("秃头", "老王");
}

5.4 构造函数泛型

main() {
  var p = Phone<String>('123456');
  print(p.mobileNumber);
}

class Phone<T> {
  final T mobileNumber;
  Phone(this.mobileNumber);
}

5.5 泛型限制, 通过 extends 关键字限定可泛型使用的类型

main() {
  var footMassage = FootMassage();
  var m = Massage<FootMassage>(footMassage);
  m.massage.doMassage();
}

class Massage<T extends FootMassage > {
  final T massage;
  Massage(this.massage);
}

class FootMassage {
  void doMassage() {
    print('脚底按摩');
  }
}

6 库

6.1 载入核心库

  1. import 后的必须参数为库 的 URI。(Uniform Resource Identifier统一资源标识符)
  2. 对于内置的库,URI 使用特殊的 dart: scheme。
  3. 对于其他的库,你可以使用文件系统路径或者 package: scheme。

示例如下图:
示例图

6.2 载入第三方库

  • pubspec.yaml声明需要引用的库,使用Packages get进行拉取。

Dart开源包
pubspec.yaml声明需要引用的库,使用Packages get进行拉取
调用:
调用

6.3 载入文件

1.新建dart文件
新建dart文件
2.载入文件
载入文件

6.4 指定库前缀

  • 关键字: as

  • 如果两个库有冲突的标识符,可以为其中一个或两个库都指定前缀;

示例如下:
两个库有冲突的标识符
指定前缀:
指定前缀

6.5 选择性载入

  • 关键字:showhide

1.新建dart文件
新建dart文件
2.选择性导入(只使用库中一部分,或者隐藏库中一部分)
选择性导入(

6.6 延迟载入

  1. 使用deferred as导入;
  2. 使用标识符调用loadLibrary()加载库;
    示例如下: 延迟载入
  • 使用 await 关键字暂停代码执行一直到库加载完成。
  • 可提高程序启动速度。
  • 用在不常使用的功能。
  • 用在载入时间过长的包。
  • 执行 A/B 测试,例如 尝试各种算法的 不同实现。

6.7 载入自定义库

  1. part 可以把一个库分开到多个 Dart 文件中。
  2. 或者我们想让某一些库共享它们的私有对象的时候,可以需要使用part。
  3. import不会完全共享作用域,而part之间是完全共享的。如果说在A库中import了B库,B库import了C库,A库是没有办法直接使用C库的对象的。而B,C若是A的part,那么三者共享所有对象。并且包含所有导入。
    载入自定义库

6.8 Flutter 一些常用库

摘自:Flutter 一些常用库

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页