一文搞定Dart入门(学习笔记)

Posted Beason_H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文搞定Dart入门(学习笔记)相关的知识,希望对你有一定的参考价值。

前言

​ 一文搞定Dart入门,建议有一定编程功底的人查看,或者作为笔记复习查阅。

​ 本文主要是早之前学习Dart的一些笔记,记录了Dart常用的知识点以及用法。很多知识点比如:抽象类,泛型,异步处理,Mixin机制等这里没有做具体的详解。

​ 后期开发学习过程中如果会持续更新…

重要概念

  • 任何保存在变量中的都是一个 对象 , 并且所有的对象都是对应一个 的实例。 无论是数字,函数和 null 都是对象。所有对象继承自Object类。
  • 尽管 Dart 是强类型的,但是 Dart 可以推断类型,所以类型注释是可选的。
  • Dart 支持泛型,如 List <int> (整数列表)或 List <dynamic> (任何类型的对象列表)。
  • Dart 支持顶级函数(例如 main() ),这些函数不会封装在一个类或者对象当中,所有的应用程序都至少有一个顶级函数,即 main() 函数 。
  • Dart 支持顶级 变量 , 同样变量绑定在类或对象上(静态变量和实例变量)
  • 与 Java 不同,Dart 没有关键字 “public” , “protected” 和 “private” 。 如果标识符以下划线(_)开头,则它相对于库是私有的
  • 标识符 以字母或下划线(_)开头,后跟任意字母和数字组合
  • Dart 语法中包含 表达式( expressions )(有运行时值)和 语句( statements )(没有运行时值)

变量

变量定义

var name = 'beason' //类型推导为string
dynamic name = 'beason' //动态类型,编译时不会进行类型推导,运行时进行类型推导
String name = "beason" //指定类型为String

思考:var, dynamic,object定义变量的区别?

所有的实例变量都隐式的生成get方法,非final变量还会生成set方法

默认值

​ 未初始化的变量默认都是Null,无论是数字还是其他类型

Final/Const

  • 使用过程中从来不会被修改的变量:final和const
  • Final 只能被设置一次:必须在构造函数体执行之前初始化
  • Const在编译时就已经固定

数据类型

Dart 语言支持以下内建类型:

Number

  • int:整数值不大于64位,值的范围从 -263 到 263 - 1
  • double:64位浮点数

intdouble 都是 num的子类,num 类型包括基本运算 +, -, /, 和 *, 以及 abs()ceil(), 和 floor(), 等函数方法

String

  • 支持内嵌${expression}表达式

    var s = 'string interpolation';
    print('Dart has $s, which is very handy.');
    
  • 支持使用”+“运算符,把多个字符串连接成一个

  • ==用来检查两个对象是否相等

  • 定义多行可以使用’’'三个点定义字符串

  • 使用r前缀,可以定义raw原始字符串(没有任何转义,\\n照样输出)

Boolean

  • bool类型,只有字面量true/false表示

List(也被称为Array)

  • 定义:var list = [1,2,3] ,推导类型为list

  • 元素访问:list[1],list[-1]

  • 在 List 字面量之前添加 const 关键字,可以定义 List 类型的编译时常量:

    var constantList = const [1, 2, 3];
    // constantList[1] = 1; // 取消注释会引起错误。
    

Map

  • 定义:var map = {“key”:“value”}
  • 元素访问:map[“key”]
  • 添加元素:map[“addKey”] = “addValue”;

Set

  • 定义:元素唯一的无序集合:var set = {1,2,3,4,5,7},类型推导为:Set

函数

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

函数示例

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
//也可以省略类型声明
isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
  • 如果函数只有一行可以:

    bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
    
  • => *expr* 语法是 { return *expr*; } 的简写

函数是一等对象

  • 可以将函数作为另一个函数的参数
  • 可以将函数赋值给任意变量

可选参数

  • 命名可选参数

    定义: {param1, param2, …}

    void enableFlags({bool bold, bool hidden}) {...}
    

    使用:paramName: value

    enableFlags(bold: true, hidden: false);
    
  • 位置可选参数

    定义: []

    String say(String from, String msg, [String device])
    

    使用:调用方法的时候,可选参数可以省略

    say('Bob', 'Howdy')
    
  • 默认参数值

    使用=号来定义可选参数默认值,如果没有提供默认值,那么默认值为null

    定义:

    /// 设置 [bold] 和 [hidden] 标志 ...
    void enableFlags({bool bold = false, bool hidden = false}) {...}
    

    使用:

    // bold 值为 true; hidden 值为 false.
    enableFlags(bold: true);
    

匿名函数

​ 多数函数是有名字的, 比如 main()printElement()。 也可以创建没有名字的函数,这种函数被称为 匿名函数, 有时候也被称为 lambda 或者 closure

​ 如果匿名函数只有一条语句同样可以使用 =>简写

​ 下面例子中定义了一个包含一个无类型参数 item 的匿名函数。 list 中的每个元素都会调用这个函数,打印元素位置和值的字符串。

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

闭包

​ 闭包:既一个函数对象,即使函数对象的调用在它的原始作用域之外,依然能够访问在它次法作用域内的变量

返回值

所有函数都会返回一个值。 如果没有明确指定返回值, 函数体会被隐式的添加 return null; 语句。

foo() {}
assert(foo() == null);

常用的操作符

类型判定运算符

  • as 将对象强制转换为特定类型
  • is 是否是某种类型,相当于java instanceof
  • is! 是否不是某种类型

条件表达式

  • condition ? expr1 : expr2

    如果条件为 true, 执行 expr1 (并返回它的值): 否则, 执行并返回 expr2 的值。

  • expr1 ?? expr2

    如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。

级联运算符 (…)

​ 级联运算符 (..) 可以实现对同一个对像进行一系列的操作。

非空调用

​ 如:a?.b 相当于 a == null ? null : a.b

三目赋值运算符

​ 如:a ??= b 相当于 a = a == null ? b : a

整除

​ 如:a ~/ b 等价于 (a /b) as int

控制流程语句

if and else

//和 javascript 不同, Dart 的判断条件必须是布尔值,不能是其他类型
if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

for loops

//方式一var message = StringBuffer('Dart is fun');for (var i = 0; i < 5; i++) {  message.write('!');}//方式二candidates.forEach((candidate) => candidate.interview());//方式三var collection = [0, 1, 2];for (var x in collection) {  print(x); // 0 1 2}

while and do-while loops

while (!isDone()) {  doSomething();}
do {  printLine();} while (!atEndOfPage());

break and continue

  • Break:停止循环
  • Continue: 跳转到下一次迭代

switch and case

​ 在 Dart 中 switch 语句使用 == 比较整数,字符串,或者编译时常量。 比较的对象必须都是同一个类的实例(并且不可以是子类), 类必须没有对 == 重写。 枚举类型 可以用于 switch 语句。

  • case 语句中,每个非空的 case 语句结尾需要跟一个 break 语句

assert

  • 如果 assert 语句中的布尔条件为 false , 那么正常的程序执行流程会被中断。
  • assert 语句只在开发环境中有效, 在生产环境是无效的; Flutter 中的 assert 只在 debug 模式 中有效。

异常

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

​ Dart 提供了 ExceptionError 类型, 以及一些子类型。 当然也可以定义自己的异常类型。 但是,此外 Dart 程序可以抛出任何非 null 对象, 不仅限 Exception 和 Error 对象。

  • 也可以throw 'beason is null’抛出任意对象

    throw FormatException('Expected at least 1 section');throw 'Out of llamas!';
    
  • 使用On来制定类型,catch捕获,try{}on Exception catch(e){}

    try {  breedMoreLlamas();} on OutOfLlamasException {  buyMoreLlamas();}
    
  • catch函数可以制定1-2个参数,第一个为异常对象,第二个为堆栈信息

    try {  // ···} on Exception catch (e) {  print('Exception details:\\n $e');} catch (e, s) {  print('Exception details:\\n $e');  print('Stack trace:\\n $s');}
    
  • 不管是否抛出异常, finally 中的代码都会被执行。 如果 catch 没有匹配到异常, 异常会在 finally 执行完成后,再次被抛出:

​ Dart 是一种基于类和 mixin 继承机制的面向对象的语言。 每个对象都是一个类的实例,所有的类都继承于 Object. 。 基于 * Mixin 继承* 意味着每个类(除 Object 外) 都只有一个超类, 一个类中的代码可以在其他多个继承类中重复使用。

使用类的成员变量

  • 使用 (.) 来引用实例对象的变量和方法
  • 使用 ?. 来代替 . , 可以避免因为左边对象可能为 null , 导致的异常。
  • 使用对象的 runtimeType 属性, 可以在运行时获取对象的类型, runtimeType 属性回返回一个 Type 对象。

类的定义用 class 关键字,如果未显式定义构造函数,会默认一个空的构造函数,这一点与 Java是一样的

通过 构造函数 创建对象。 构造函数的名字可以是 *ClassName* 或者 `ClassName.identifier

构造函数

默认构造函数

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

构造函数不被继承

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

命名构造函数

class Point {  num x, y;  Point(this.x, this.y);  // 命名构造函数,可以有多个  Point.origin() {    x = 0;    y = 0;  }}

重定向构造函数

​ 有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。 重定向构造函数的函数体为空, 构造函数的调用在冒号 (😃 之后。

class Point {  num x, y;  // 类的主构造函数。  Point(this.x, this.y);  // 指向主构造函数  Point.alongXAxis(num x) : this(x, 0);}

常量构造函数

​ 如果该类生成的对象是固定不变的, 那么就可以把这些对象定义为编译时常量。 为此,需要定义一个 const 构造函数, 并且声明所有实例变量为 final

class ImmutablePoint {  static final ImmutablePoint origin =      const ImmutablePoint(0, 0);  final num x, y;  const ImmutablePoint(this.x, this.y);}

工厂构造函数

​ 当执行构造函数并不总是创建这个类的一个新实例时,则使用 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);  }}

工厂构造函数无法访问 this。

调用父类非默认构造函数

​ 默认情况下,子类的构造函数会自动调用父类的默认构造函数(匿名,无参数)。 父类的构造函数在子类构造函数体开始执行的位置被调用。

执行顺序如下:

  1. initializer list (初始化参数列表)
  2. superclass’s no-arg constructor (父类的无名构造函数)
  3. main class’s no-arg constructor (主类的无名构造函数)

抽象类

​ Dart 中并没有 interface 关键字,只有 abstract 来修饰"抽象类",但是,这里的抽象类既可以被继承(extends),也可以被实现(implements),但是抽象类不能实例化。如果希望抽象类能够被实例化,那么可以通过定义一个 工厂构造函数 来实现。

// 这个类被定义为抽象类,// 所以不能被实例化。abstract class AbstractContainer {  // 定义构造行数,字段,方法...  void updateChildren(); // 抽象方法。}

隐式接口

​ 每个类都隐式的定义了一个接口,接口包含了该类所有的实例成员及其实现的接口。

扩展类(继承)

​ 使用 extends 关键字来创建子类, 使用 super 关键字来引用父类

noSuchMethod()

​ 当代码尝试使用不存在的方法或实例变量时, 通过重写 noSuchMethod() 方法,来实现检测和应对处理

除非符合下面的任意一项条件, 否则没有实现的方法不能够被调用:

  • receiver 具有 dynamic 的静态类型 。
  • receiver 具有静态类型,用于定义为实现的方法 (可以是抽象的), 并且 receiver 的动态类型具有 noSuchMethod() 的实现, 该实现与 Object 类中的实现不同。

枚举类型

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

  • 枚举类中每一个值都有一个index getter方法,返回对应的索引
  • 枚举类型不能被子类化,混合或者实现
  • 枚举类型不能被显示实例化

Mixin

​ Mixin 是复用类代码的一种途径, 复用的类可以在不同层级,之间可以不存在继承关系。具体理解可以看另一篇文章小白都能看懂的关于Mixin机制的理解

泛型

​ 在 API 文档中你会发现基础数组类型 List 的实际类型是 List<E> 。 <…> 符号将 List 标记为 泛型 (或 参数化) 类型。 这种类型具有形式化的参数。 通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。

定义

  • 使用 <…> 来声明泛型
  • 通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。
  • List 定义的泛型*(或者 参数化) 类型,定义为List<E>

限制泛型类型

​ 使用泛型类型的时候, 可以使用 extends 实现参数类型的限制

class Foo<T extends SomeBaseClass> {  // Implementation goes here...  String toString() => "Instance of 'Foo<$T>'";}class Extender extends SomeBaseClass {...}

库和可见性

importlibrary 指令可以用来创建一个模块化的,可共享的代码库。 库不仅提供了 API ,而且对代码起到了封装的作用: 以下划线 (_) 开头的标识符仅在库内可见。 每个 Dart 应用程序都是一个库 ,虽然没有使用 library 指令。

使用库

//直接导入import 'dart:html';//指定库前缀import 'package:lib2/lib2.dart' as lib2;//导入库的某一部分import 'package:lib1/lib1.dart' show foo;//延迟加载库,当需要使用时候:await hello.loadLibrary();import 'package:greetings/hello.dart' deferred as hello;
  1. loadLibrary()可以调用多次,但是只载入一次

  2. 延迟加载库的常量在导入的时候是不可用的,只有当库加载完成的时候,库中常量才可以使用

异步支持

​ Dart 库中包含许多返回 Future 或 Stream 对象的函数. 这些函数在设置完耗时任务(例如 I/O 曹组)后, 就立即返回了,不会等待耗任务完成。 使用 asyncawait 关键字实现异步编程。

处理 Future

  • 使用 asyncawait.
  • 使用 Future API

声明异步函数

  • 函数体被 async 标示符标记的函数,即是一个_异步函数_。

处理 Stream

  • 使用 async 和 一个 异步循环await for)。
  • 使用 Stream API

总结

​ 文章对大部分知识点做了个简单的介绍,具体的理解可能需要一点语言功底,本文只作为学习笔记/手册记录,如果需要详细学习Dart这门语言建议:[Dart入门](

以上是关于一文搞定Dart入门(学习笔记)的主要内容,如果未能解决你的问题,请参考以下文章

前端进阶:一文轻松搞定webpack基础知识进阶与调优

一文看懂低代码,5分钟从入门到原理全搞定

Spring入门到精通,一文带你轻松搞定Spring!

一文搞定考研408的《操作系统》

一文搞定json解析和封装问题,手把手带你学习CJSON开源代码

一文搞定深度学习建模预测全流程(Python)