6

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

 2 years ago
source link: https://blog.csdn.net/huangbiao86/article/details/120787208
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

专栏收录该内容
6 篇文章 1 订阅

​ 一文搞定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; // 取消注释会引起错误。
    
  • 定义:var map = {“key”:“value”}
  • 元素访问:map[“key”]
  • 添加元素:map[“addKey”] = “addValue”;
  • 定义:元素唯一的无序集合: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入门](


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK