Dart 语法学习笔记

变量

声明变量几种方式:

1. var name     = "Tim";   //自动推倒类型(infer)为string
2. String name  = "Tim";   //强类型定义
3. dynamic name = "Tim";   //可以修改变量类型 name = 4.0;
4. final name   = "Tim";   //首次使用时执行一次
5. const name   = "Tim";   //类似全局常量或者static,编译期间确定值

如果没有赋初始值,默认变量初始值为null。

内置类型

  1. Numbers: 编译期间的数字类型的常量

    • int: 不大于64位,具体取决于平台
    • double: 64位

    int 类实现了位移运算符;
    支持0x十六进制;
    浮点型支持科学计数法

  2. Strings: UTF-16 unicode 编码

    语法跟python类似

    • &{express} 可以嵌入变量或者表达式
    • ”’ ”’ 或者 “”” “””,可以多行显示
    • r”, raw字符串
    • In Dart, runes are the UTF-32 code points of a string.
  3. Booleans: 同样是编译期间常量。

    • bool 标识符,true & false
    • if (nonbooleanValue) 这样比较是不行的,必须显示的比较或者调用类isEmpty方法。
  4. Lists: 数组

    • 如果想要声明一个编译期常量的数组:var constantList = const [1, 2, 3]; //必须指定为const
  5. Maps: 字典 同js

  6. Runes: UTF-32 字符串。比如一些符号,表情等。\uXXXX

  7. Symbols: 不会用到。针对API推断标识符有用。

函数

Dart是一个真正的面向对象编程语言,一切都是对象,函数也是一个对象,它的类型是Function。

跟c语言函数语法一样,但是可以省略返回值类型和参数类型。

也有自己的速写语法:

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

=> expr{ return expr; } 的简写。expr只能是一个语句,否则必须用{}方式。

一、参数

1. 函数调用时,可以使用 name:value方式制定参数。顺序可以不是声明顺序。
2. @require 关键字,标示该参数必须传入。
3. 可选参数,使用[]扩起来。必须放到参数的最后位置,且不能存在多个[]的可选位置参数。
4. 参数可以设置默认值,如果没有设置默认值,默认为null。

二、.. 操作符,可以看作是链式编程的语法。object.func1()..func2()..func3();
三、函数可以作为参数传递给函数,作用同对象参数一样。
四、匿名函数、lambda表达式、闭包。是一个概念。
五、返回值:所有函数都有一个返回值,默认返回return null;

运算符

很多操作跟c运算符一致,这里不做过多介绍。下面只介绍特殊运算符:

~/: 除法,返回整数

as: 类型判断

is、is!: 类型检测

..: 严格来说,double dot不是操作符,而是Dart的语法。对同一个对象做一系列操作,类似链式编程。

??=: 赋值,只有当左值为null的时候,才赋值。
// 只有当b是null的时候,给b赋值value; 否则b保持原值不变
b ??=: value;

??: 条件运算符,简化if..else语句。expr1 ?? expr2,如果expr1不为null, 返回expr1; 否则返回expr2。

?.: 类似.操作符,获取成员。问号的作用是标示对象可以是null

控制流

  • if..else: 条件必须是boolean类型
  • for:
    • 传统for语法
    • for-in:可迭代的类或者类型才支持。例如:List, Set等
  • While and do-while
  • Break and continue
  • Switch and case: int和string都可以作为case条件;每个case后必须有break语句;不支持空case;
var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed:
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}
  • Assert

异常处理

  • Throw: 可以抛出非null的任何对象,包括exception和error对象。
  • Catch: 语法如下:on可以捕获具体类型的exception;catch 可以跟on一起,也可以单独使用。最多包含两个参数,e是抛出的异常,s是堆栈信息。
try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

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: 捕获异常后后会继续执行finally中的内容。
try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}

  • 使用类成员: 使用.运算符引用对象成员和方法。
// If p is non-null, set its y value to 4.
p?.y = 4;
  • 使用构造函数: Dart 2中new操作符可选。构造函数可以是类名,也可以是类名.标识符。
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
  • 获取对象类型:使用runtimeType属性。(Object对象定义,获取运行时对象类型)

  • 成员变量
    没有public、private、protected关键字。
    不需要设置成员变量默认值,不初始化的变量默认null。
    默认会对成员变量生成隐式的get和set方法。

  • 构造函数
    构造函数可以是跟类名一样的名字,也可以声明其他名字。

class Point {
  num x, y;

  Point(num x, num y) {
    // Use this only when there is a name conflict
    this.x = x;
    this.y = y;
  }
  
  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  // Point(this.x, this.y); 等同于上面的构造函数,写法更简单
  
  // Named constructor:使用:Point p = Point.origin();
  Point.origin() {
    x = 0;
    y = 0;
  }
}

如果不写构造函数,会默认生成一个构造函数;默认生成的构造函数跟类同名,没有参数。

构造函数不能继承。默认子类会调用基类的默认构造函数或者无参数构造函数。

跟C++一样,Dart也有初始化列表(initializer list)。初始化列表要写在调用基类构造函数之前。

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

重定向构造函数:重定向构造函数的函数体必须为空,通过冒号在后面定向到其他构造函数.

class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

常量构造函数:可以创建一个编译时的常量对象,对象构造函数参数必须时常量。用于创建一个不变的对象(内部成员不会改变)

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

工厂构造函数:不能直接使用this。可以从cache获取实例,也可能创建子类型的对象。

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

  // _cache is library-private, thanks to
  // the _ in front of its name.
  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);
  }
}
  • 成员函数
    getter和setter方法,是默认生成用于存取成员变量的成员函数。也可以显式声明(使用get和set关键字)
 class Rectangle {
 num left, top, width, height;

 Rectangle(this.left, this.top, this.width, this.height);

 // Define two calculated properties: right and bottom.
 num get right => left + width;
 set right(num value) => left = value - width;
 num get bottom => top + height;
 set bottom(num value) => top = value - height;
 }

抽象方法:类似C++中的虚基类中的虚函数,基类中没有实现,子类实现。

  • 抽象类:
    跟C++不同的是,可以通过工厂构造函数(factory constructor)创建实例。

  • 隐含接口(Implicit interfaces):使用implements关键字,可以实现类的方法,可以实现多重继承。

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(String who) => 'Hello, $who. I am $_name.';
 }

// An implementation of the Person interface.
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

class Point implements Comparable, Location {...}
  • 扩展一个类
    关键字extends创建子类,使用super指向其基类。
    @override 关键字用来覆盖基类的实现。
    covariant 关键字:表示收紧子类型

    class Animal {
    void chase(Animal x) { ... }
    }
    
    class Mouse extends Animal { ... }
      
    class Cat extends Animal {
      //只能传Mouse和其子类
      void chase(covariant Mouse x) { ... }
    }
    

    不能访问一个不存在的成员函数,但是可以通过覆盖noSuchMethod()方法,使代码不抛出异常。

  • 枚举类型:可以表示固定的常数的一种特殊的类。默认值index从0开始。

    enum Color { red, green, blue } //使用enum关键字定义枚举
    
    assert(Color.red.index == 0);
    assert(Color.green.index == 1);
    assert(Color.blue.index == 2);
    

    枚举类型使用的限制:

    1. 不能继承,混合和实现一个枚举。
    2. 不能显式的实现一个枚举类。
  • 向类中添加特性:使用mixins技术(类似多重继承)
    关键字with

    class T = A with S;
    那我们得到的class T是怎么样的呢?假设MA表示A中的所有方法,MS表示S中的所有方法,那么T中的方法集合为:MS U (MA - MS)

    复杂一点的情况:class T = B with A, S; == class T = (B with A) with S;

  • 类成员和方法:同样使用static关键字。

泛型

可以在运行时判断泛型类型内容的具体type。其他方面跟java或者c++差不多。

库和可见性

  • 使用import导入要使用的库。
  • 如果导入的多个库中,有同名类或者函数,可以通过别名区分。关键字as。类似c++中的namespace。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
  • 也可以仅仅导入库中的部分内容 showhide关键字
// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
  • 懒加载库 deferred as关键字
import 'package:greetings/hello.dart' deferred as hello;

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}
  • 如何实现库。单独章节进行讲解。

异步支持

关键字asyncawait支持异步编程。

生成器

参考python中的生成器。
需要后续加强了解

可调用的类

Dart 语言中为了能够让类像函数一样能够被调用,可以实现call()方法。
具体使用的场景,需要调研

隔离

沙盒?

Typedefs

Dart中,函数也是对象。Function关键字,typedefs 可以给函数设置别名。

元数据

A metadata annotation begins with the character @, followed by either a reference to a compile-time constant (such as deprecated) or a call to a constant constructor.

Two annotations are available to all Dart code: @deprecated and @override.

注释

  • 单行 //
  • 多行 /* */
  • 文档注释 /// 或者 /**
    原文作者:TimBao
    原文地址: https://www.jianshu.com/p/4cb312e13f65
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞