【Flutter从0到1】番茄计时APP:Dart 语言速览基础篇

707 阅读9分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

目录

1.【Flutter从0到1】番茄计时APP:项目筹备

2.【Flutter从0到1】番茄计时APP:原型图+功能梳理

3.【Flutter从0到1】番茄计时APP:环境搭建

4.【Flutter从0到1】番茄计时APP:跑通第一个页面

5.【Flutter从0到1】番茄计时APP:Dart 语言速览基础篇

就在我准备大展身手的时候,突然发现,我根本没了解过Dart语言,写个寂寞啊。

好家伙,准备当司机,发现自己不会开车。。。

所以利用其他语言的经验,对着文档,总结了两篇速览,快速掌握Dart语言,本篇是Dart语言-基础篇。

注意:这里假设你已经有使用其它语言进行编程的经验,如果什么经验都没有,那读起来可能像是在读天书。

基础概念

Dart 是一种针对客户优化的语言,可在任何平台上开发快速的应用程序。其目标是为多平台开发提供最高效的编程语言,Dart 也是Flutter的基础。 Dart 作为 Flutter 应用程序的编程语言,为驱动应用运行提供了环境,同时 Dart 还支持许多核心的开发任务,例如格式化,分析和代码测试。

经典"Hello,World"

void main(){
  print('Hello, World!');
}

一些基础概念

  1. 所有变量引用都是对象,每个对象都是一个类的实例,所有的类都继承于Object类。(使用面向对象语言的同学应该非常容易理解)
  2. 尽管 Dart 是强类型语言,但是在声明变量时指定类型是可选的,因为 Dart 可以进行类型推断。(使用起来和JavaScript类似)。
  3. Dart 支持顶级函数(例如 main 方法),同时还支持定义属于类或对象的函数(即静态和实例方法)。还可以在函数中定义函数(嵌套或局部函数)。
  4. 同样Dart也支持泛型,比如 List(表示一组由 int 对象组成的列表)或 List(表示一组由任何类型对象组成的列表)。
  5. Dart 工具可以显示 警告 和 错误 两种类型的问题。警告表明代码可能有问题但不会阻止其运行。错误分为编译时错误和运行时错误;编译时错误代码无法运行;运行时错误会在代码运行时导致异常。(和其他语言一致)。
  6. 变量

    创建一个变量并初始化示例:

    // 基础用法
    var name ='Bob';
    
    // 声明为Object
    Object name = 'Bob';
    
    // 指定类型
    String name = 'Bob';
    

    默认值:

    在 Dart 中,未初始化以及可空类型的变量拥有一个默认的初始值 null。即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。

    Final和Const

    如果你不想更改一个变量,可以使用关键字 final 或者 const 修饰变量,这两个关键字可以替代 var 关键字或者加在一个具体的类型前。一个 final 变量只可以被赋值一次;一个 const 变量是一个编译时常量(const 变量同时也是 final 的)。顶层的 final 变量或者类的 final 变量在其第一次使用的时候被初始化。

    Late variables(延迟变量)

    Dart 2.12 添加了 late 修饰符,它有两个用例:

    1. 声明一个在声明后初始化的不可为空的变量。
    2. 延迟初始化一个变量。

    通常 Dart 的控制流分析可以检测到一个不可为空的变量在使用之前何时设置为非空值,但有时分析会失败。两种常见的情况是顶级变量和实例变量: Dart 经常无法确定它们是否被设置,所以它不会尝试。

    如果您确定变量在使用之前已设置,但 Dart 不允许,可以通过将变量标记为延迟来修复错误,示例如下:

    lateString description;
    void main(){
      description ='Feijoada!';
      print(description);
    }
    

    备注:关于空安全的内容,在下一篇文章进阶篇中有详细介绍。

    数据类型

    Dart 语言支持下列内容:

    • Numbers (int, double)
    • Strings (String)
    • Booleans (bool)
    • Lists (也被称为 arrays)
    • Sets (Set)
    • Maps (Map)
    • Runes (常用于在 Characters API 中进行字符替换)
    • Symbols (Symbol)
    • The value null (Null)

    这部分比较简单,没啥值得注意的点,看文档就好了:dart.cn/guides/lang…

    函数

    整体和Java差不多,可以有两种形式的参数:必要参数 和 可选参数。必要参数定义在参数列表前面,可选参数则定义在必要参数后面。

    1.可选参数:命名参数、位置参数、默认参数

    // 定义函数时,使用 {参数1, 参数2, …} 来指定命名参数:
    void enableFlags({bool? bold, bool? hidden}) {...}
    
    // 使用 [] 将一系列参数包裹起来作为位置参数:
    String say(String from, String msg, [String? device]) {
      var result = '$from says $msg';
      if (device != null) {
        result = '$result with a $device';
      }
      return result;
    }
                                                  
    // 默认参数
    void enableFlags({bool bold = false, bool hidden = false}) {...}
    enableFlags(bold: true);
    

    2.匿名函数

    大多数方法都是有名字的,比如 main() 或 printElement()。你可以创建一个没有名字的方法,称之为 匿名函数、 Lambda 表达式 或 Closure 闭包。你可以将匿名方法赋值给一个变量然后使用它,比如将该变量添加到集合或从中删除。

    匿名方法看起来与命名方法类似,在括号之间可以定义参数,参数之间用逗号分割。

    // 后面大括号中的内容则为函数体:
    ([[类型] 参数[, …]]) {
      函数体;
    };
    
    // 示例
    const list = ['apples', 'bananas', 'oranges'];
    list.forEach((item) {
      print('${list.indexOf(item)}: $item');
    });
    
    
    

    运算符

    描述运算符
    一元后缀表达式++ 表达式-- () [] . ?. !
    一元前缀-表达式 !表达式 ~表达式 ++表达式 --表达式
    乘除法* / % ~/
    加减法+ -
    位运算<< >> >>>
    二进制与&
    二进制异或
    二进制或
    关系和类型测试>= ]]> <= < as is is!
    相等判断== !=
    逻辑与&&
    逻辑或
    空判断??
    条件表达式表达式 1 ? 表达式 2 : 表达式 3
    级联.. ?..
    赋值= *= /= += -= &= ^= 等等……

    流程控制

    可以使用下面的语句来控制 Dart 代码的执行流程:

    • if 和 else
    • for 循环
    • while 和 do-while 循环
    • break 和 continue
    • switch 和 case
    • assert

    使用 try-catch 和 throw 也能影响控制流。

    流程控制这里和Java、JS等语言没啥大区别,文档地址:dart.cn/guides/lang…

    异常处理

    Dart 代码可以抛出和捕获异常。异常表示一些未知的错误情况,如果异常没有捕获则会被抛出从而导致抛出异常的代码终止执行。

    与 Java 不同的是,Dart 的所有异常都是非必检异常,方法不必声明会抛出哪些异常,并且你也不必捕获任何异常。

    Dart 提供了 Exception 和 Error 两种类型的异常以及它们一系列的子类,你也可以定义自己的异常类型。但是在 Dart 中可以将任何非 null 对象作为异常抛出而不局限于 Exception 或 Error 类型。

    1. 抛出异常
    throwFormatException('Expected at least 1 section');
    
    1. 捕获异常
    try {
      breedMoreLlamas();
    } on OutOfLlamasException {
      buyMoreLlamas();
    }
    
    1. Finally

    无论是否抛出异常,finally 语句始终执行,如果没有指定 catch 语句来捕获异常,则异常会在执行完 finally 语句后抛出:

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

    Dart 是支持基于 mixin 继承机制的面向对象语言,所有对象都是一个类的实例,而除了 Null 以外的所有的类都继承自 Object 类。 基于 mixin 的继承 意味着尽管每个类(top class Object? 除外)都只有一个超类,一个类的代码可以在其它多个类继承中重复使用。 扩展方法 是一种在不更改类或创建子类的情况下向类添加功能的方式。

    1. 和Java不同的是,在new一个对象的时候,new关键字可以省略,示例:
    // 命名方式可以为类名
    var p1 = Point(2, 2);
    // 命名方式为类名.标识符
    var p2 = Point.fromJson({'x': 1, 'y': 2});
    
    1. 构造函数
    class Point {
      double x = 0;
      double y = 0;
    
      Point(double x, double y) {
        // See initializing parameters for a better way
        // to initialize instance variables.
        this.x = x;
        this.y = y;
      }
    }
    
    1. 命名构造函数

    记住构造函数是不能被继承的,这将意味着子类不能继承父类的命名式构造函数,如果你想在子类中提供一个与父类命名构造函数名字一样的命名构造函数,则需要在子类中显式地声明。

    const double xOrigin = 0;
    const double yOrigin = 0;
    
    class Point {
      final double x;
      final double y;
    
      Point(this.x, this.y);
    
      // Named constructor
      Point.origin()
          : x = xOrigin,
            y = yOrigin;
    }
    
    1. 抽象类

    使用关键字 abstract 标识类可以让该类成为 抽象类,抽象类将无法被实例化。抽象类常用于声明接口方法、有时也会有具体的方法实现。如果想让抽象类同时可被实例化,可以为其定义 工厂构造函数。

    抽象类常常会包含 抽象方法。下面是一个声明具有抽象方法的抽象类示例:

    // This class is declared abstract and thus
    // can't be instantiated.
    abstract class AbstractContainer {
      // Define constructors, fields, methods...
      void updateChildren(); // Abstract method.
    }
    
    1. 继承与多态
    • 子类继承,必须实现抽象方法
    • dart中的多态体现在方法重写,向上转型
    1. 接口

    dart中类就是接口,和声明抽象类一样,一般是用abstract修饰

    泛型

    泛型常用于需要要求类型安全的情况,在创建对象时可以定义泛型类型,和Java几乎一致,但是它也会对代码运行有好处:

    • 适当地指定泛型可以更好地帮助代码生成。
    • 使用泛型可以减少代码重复。

    和Java的区别

    • Java中的泛型信息是编译时的,泛型信息在运行时是不存在的。
    • Dart的泛型类型是固化的,在运行时也有可以判断的具体类型。

    注释

    Dart 支持单行注释、多行注释和文档注释。

    1.单行注释以 // 开始。所有在 // 和该行结尾之间的内容均被编译器忽略。

    void main(){   // TODO: refactor into an AbstractLlamaGreetingFactory?   
      print('Welcome to my Llama farm!');
    }
    

    2.多行注释以 /* 开始,以 / 结尾。所有在 / 和 */ 之间的内容均被编译器忽略(不会忽略文档注释),多行注释可以嵌套。

    void main() {
      /*
       * This is a lot of work. Consider raising chickens.
    
      Llama larry = Llama();
      larry.feed();
      larry.exercise();
      larry.clean();
       */
    }
    

    想要了解更多内容,建议看官方文档:dart.cn/samples