Dart语法层次的触动

290 阅读3分钟

我所使用的版本

image.png

Dart语法

变量

每一个使用Dart开发的app都使用void main函数,返回值是void。尽管Dart是类型安全的语言,声明变量可以使用var关键字,可以不需要指定变量的类型,由于类型推断,Dart可以推断出变量类型的类型。示例代码如下所示:

void main() {
  var age = 10;
  var name = "caicai";
}

使用late修饰的变量,有两方面的作用:

  1. 声明一个非空变量,该变量在声明后初始化。
  2. 延迟初始化变量。 如果未能初始化late变量,则使用该变量时会发生运行时错误。

要在运行时获取对象的类型,可以使用类Object的属性runtimeType,该属性返回一个Type对象。也可以用关键字is来判断是否是某种类型,示例代码如下:

void main() {
  var age = 10;
  var name = "caicai";
  print('The type of age is ${age is int} and the type of name is ${name.runtimeType}');
}

运行结果如下图所示:

image.png

扩展方法

扩展方法的定义如下所示:

extension <extension name>? on <type> { // <extension-name> is optional
  (<member definition>)* // Can provide one or more <member definition>.
}

当你使用别人的API或实现一个广泛使用的库时,更改API通常是不切实际甚至不可能的。但你可能仍然想添加一些功能,这时候就可以用到扩展方法。扩展不仅可以定义方法,还可以定义其他成员,例如getter、setter 和运算符。此外,扩展可以具有名称,这在发生 API 冲突时非常有用。示例代码如下:

extension on String {
  int parseInt(){
    return int.parse(this);
  }
}
void main() {
  var value = "123".parseInt();
  print('The type of value is ${value} and the type of value is ${value.runtimeType}');
}

也许有人会说我们可以继承某个库的类来增加相应的属性或者方法,鉴于Dart是单继承的编程语言,我们就不能继承其他的类;还有人会说我们可以增加封装方法来增加相应的方法来实现相应的逻辑,当团队多人协作同一个项目库时候,可能会有多个顶层不同名称的方法来实现同一逻辑,从而浪费了人力。扩展方法同时还在语法调用层面有不可比拟的优越性,和实例方法调用没有什么区别。

可调用对象

在Dart中,可调用对象是定义了特殊call()方法的类的实例。这允许你像调用函数一样“调用”该对象。示例代码如下所示:

class Greeter {
  String call(String name) {
    return 'Hello, $name!';
  }
}

void main() {
  final greeter = Greeter();

  // Object used like a function!
  print(greeter('Flutter')); // Output: Hello, Flutter!
}

单继承

Dart支持单继承,但是可以实现多个接口。每个类都隐式地定义了一个接口,该接口包含该类及其实现的所有接口的所有实例成员。如果您想要创建一个类 A,使其支持类 B的API,而无需继承类B的实现,那么类A应该实现类B的接口。 对于常见或广泛使用的实用程序和功能,请考虑使用顶级函数而不是静态方法。 final vs const final修饰的var代表只能赋值一次的变量;const修饰的var代表编译期常量。实例变量可以用final修饰,不可以用const修饰。虽然final修饰的对象不能被修改,但其字段可以更改。相比之下,const对象及其字段则不能被更改:它们是不可变的。

混合

Mixins是一种定义可以“继承”多个类的层次结构中重用的代码的方式。它旨在批量提供成员实现。示例代码如下:

class Musician {
  musicianMethod() {
    print('Playing music!');
  }
}

mixin MusicalPerformer on Musician {
  performerMethod() {
    print('Performing music!');
    super.musicianMethod();
  }
}

class SingerDancer extends Musician with MusicalPerformer { }

main() {
  SingerDancer().performerMethod();
}

异步

Dart为了避免回调地狱,并且为了使代码可读性更高,通过使用async和await关键字来实现异步方法的声明和调用。async声明的方法可以理解为耗时的方法。示例代码如下所示:

const oneSecond = Duration(seconds: 1);
// ···
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}

void main() {
   printWithDelay("hello async");
}

getters和setters

当您需要对属性进行比简单字段允许的更多的控制时,您可以定义getter和setter。

class MyClass {
  int _aProperty = 0;

  int get aProperty => _aProperty;

  set aProperty(int value) {
    if (value >= 0) {
      _aProperty = value;
    }
  }
}

void main() {
  var myClass = MyClass();
  print("before ${myClass.aProperty}");
  myClass._aProperty = 10;
  print("after ${myClass.aProperty}");

}

如上面示例代码所示,我们经常声明private属性,然后对外开放getters和setters方法来对private属性操作。

级联

要对同一对象执行一系列操作,请使用级联(..)。示例代码如下所示:

class Person {
  late int age;
  late String name;
  void setName(String name) {
    this.name = name;
  }
  void setAge(int age) {
    this.age = age;
  }

  @override
  String toString() {
    print("Person{name: $name, age: $age}");
    return "Person{name: $name, age: $age}";
  }
  void cascades() {
    print("cascades function");
  }
}

void main() {
  var person = Person();
  person
    ..setName("Bob")
    ..setAge(25)
    ..toString()
    ..cascades();


}

导入

要访问其他库中定义的API,请使用import。可以导入其他库的某部分(show),也可以导入某部分除外的其他部分(hide)。如果导入两个具有冲突标识符的库,则可以为其中一个或两个库指定前缀(as)。延迟加载(也称为延迟加载)允许Web应用程序在需要库时按需加载库,要延迟加载库,首先使用deferred as导入它。

总结

语法层次以及关键字的熟悉程度会精进我们的开发技能,最终会增强我们解决问题的能力;希望你从语法层面能喜欢Dart,能开发出优秀的应用。希望文章对您有所帮助,如有纰漏,希望您不吝指出。