Dart 关键字【2】

想要写好Flutter,那么对Dart的基本关键字的掌握是必不可少的,今天就再探究一下其他的关键字。

as is si!

as is is!,运算符用于运行时处理类型检查:

obj实现了T的接口时,obj is Ttrue,obj as T可以将obj 类型转换成T类型:


class Person {
  void play(){
    print('person');
  }
}
class PersonSub extends Person{}
class Person2 {
    void play(){
    print('person2');
  }
}

 Person person = PersonSub();
 if(person is Person2){
 (person as Person2).play();
 }
 if(person is PersonSub){
   (person as PersonSub).play();
 }

person类型是Person2执行第一个if函数,如果直接(person as Person2).play();,则会崩溃,每次转换类型的时候,提交校验a is T是有必要的。

enum

枚举类型也称为 enumerationsenums , 是一种特殊的类,用于表示数量固定的常量值。

throw catch on final rethrow

捕获异常可以避免异常继续传递(除非重新抛出(rethrow )异常)。 可以通过捕获异常的机会来处理该异常:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

通过指定多个 catch 语句,可以处理可能抛出多种类型异常的代码。 与抛出异常类型匹配的第一个 catch 语句处理异常。 如果 catch 语句未指定类型, 则该语句可以处理任何类型的抛出对象:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // 一个特殊的异常
  buyMoreLlamas();
} on Exception catch (e) {
  // 其他任何异常
  print('Unknown exception: $e');
} catch (e) {
  // 没有指定的类型,处理所有异常
  print('Something really unknown: $e');
}

如上述代码所示,捕获语句中可以同时使用 oncatch ,也可以单独分开使用。 使用 on 来指定异常类型, 使用 catch 来 捕获异常对象。

catch() 函数可以指定1到2个参数, 第一个参数为抛出的异常对象, 第二个为堆栈信息 ( 一个 StackTrace 对象 )。

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

如果仅需要部分处理异常, 那么可以使用关键字 rethrow 将异常重新抛出。

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

不管是否抛出异常, finally 中的代码都会被执行。 如果 catch 没有匹配到异常, 异常会在 finally 执行完成后,再次被抛出:

try {
  breedMoreLlamas();
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}

任何匹配的 catch 执行完成后,再执行 finally

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}

factory

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

以下示例演示了从缓存中返回对象的工厂构造函数:

class Logger {
  final String name;
  bool mute = false;

  // 从命名的 _ 可以知,
  // _cache 是私有属性。
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

const

使用过程中从来不会被修改的变量, 可以使用 final 或 const, 而不是 var 或者其他类型, Final 变量的值只能被设置一次; Const 变量在编译时就已经固定 (Const 变量 是隐式 Final 的类型.) 最高级 final 变量或类变量在第一次使用时被初始化。

提示: 实例变量可以是 final 类型但不能是 const 类型。 必须在构造函数体执行之前初始化 final 实例变量 —— 在变量声明中,参数构造函数中或构造函数的初始化列表中进行初始化。

创建和设置一个 Final 变量:

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

final 不能被修改:

name = 'Alice'; // Error: 一个 final 变量只能被设置一次。

如果需要在编译时就固定变量的值,可以使用 const 类型变量。 如果 Const 变量是类级别的,需要标记为 static const。 在这些地方可以使用在编译时就已经固定不变的值,字面量的数字和字符串, 固定的变量,或者是用于计算的固定数字:

const bar = 1000000; // 压力单位 (dynes/cm2)
const double atm = 1.01325 * bar; // 标准气压

operator

重写运算符,下面的运算符可以被重写。

< + | []
> / ^ []
<= ~/ & ~
>= * << ==
% >>

提示: 你可能会被提示 != 运算符为非可重载运算符。 因为 e1 != e2 表达式仅仅是 !(e1 == e2) 的语法糖。

下面示例演示一个类重写 + 和 - 操作符:

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // 运算符 == 和 hashCode 部分没有列出。 有关详情,请参考下面的注释。
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

如果要重写 == 操作符,需要重写对象的 hashCode getter 方法。 重写 == 和 hashCode 的实例,参考 Implementing map keys.

part part of

covariant

Function

Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象,并且有它的类型 Function 。 这也意味着函数可以被赋值给变量或者作为参数传递给其他函数。 也可以把 Dart 类的实例当做方法来调用。 有关更多信息,参考 Callable classes.

已下是函数实现的示例:

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

虽然在 Effective Dart 中推荐 公共API中声明类型, 但是省略了类型声明,函数依旧是可以正常使用的:

isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

如果函数中只有一句表达式,可以使用简写语法:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr 语法是 { return expr; } 的简写。 => 符号 有时也被称为 箭头 语法。

提示: 在箭头 (=>) 和分号 (😉 之间只能使用一个 表达式 ,不能是 语句 。 例如:不能使用 if 语句 ,但是可以是用 条件表达式.

with

default

return yield

deferred hide

延迟加载库
Deferred loading (也称之为 lazy loading) 可以让应用在需要的时候再加载库。 下面是一些使用延迟加载库的场景:

  • 减少 APP 的启动时间。
  • 执行 A/B 测试,例如 尝试各种算法的 不同实现。
  • 加载很少使用的功能,例如可选的屏幕和对话框。

要延迟加载一个库,需要先使用 deferred as 来导入:

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

当需要使用的时候,使用库标识符调用 loadLibrary() 函数来加载库:

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

在一个库上你可以多次调用 loadLibrary() 函数。但是该库只是载入一次。

使用延迟加载库的时候,请注意一下问题:

延迟加载库的常量在导入的时候是不可用的。 只有当库加载完毕的时候,库中常量才可以使用。
在导入文件的时候无法使用延迟库中的类型。 如果你需要使用类型,则考虑把接口类型移动到另外一个库中, 让两个库都分别导入这个接口库。
Dart 隐含的把 loadLibrary() 函数导入到使用 deferred as 的命名空间 中。 loadLibrary() 方法返回一个 Future。

show hide

导入库的一部分
如果你只使用库的一部分功能,则可以选择需要导入的 内容。例如:

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

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;

参考

posted @ 2020-09-07 14:27  ifgyong  阅读(383)  评论(0编辑  收藏  举报