Dart 语言了解

Dart 语言了解

概念

当您了解Dart语言时,请记住以下事实和概念:

  • 您可以放在变量中的所有内容都是一个对象,每个对象都是一个类的实例。偶数,函数和 null对象。所有对象都从Object类继承。

  • 尽管Dart是强类型的,但类型注释是可选的,因为Dart可以推断类型。在上面的代码中,number 推断为类型int。如果要明确说明不需要任何类型,请 使用特殊类型dynamic。

  • Dart支持泛型类型,如List<int>(整数列表)或List<dynamic>(任何类型的对象列表)。

  • Dart支持顶级函数(例如main()),以及绑定到类或对象的函数(分别是静态和实例方法)。您还可以在函数内创建函数(嵌套函数或本地函数)。

  • 类似地,Dart支持顶级变量,以及绑定到类或对象的变量(静态和实例变量)。实例变量有时称为字段或属性。

  • 与Java,飞镖不具备关键字public,protected和private。如果标识符以下划线(_)开头,则它对其库是私有的。有关详细信息,请参阅 库和可见性。

  • 标识符可以以字母或下划线(_)开头,后跟这些字符加数字的任意组合。

  • Dart有两个表达式(具有运行时值)和 语句(不具有)。例如,条件表达式 condition ? expr1 : expr2的值为expr1或expr2。将其与if-else语句进行比较,该语句没有任何值。语句通常包含一个或多个表达式,但表达式不能直接包含语句。

  • Dart工具可以报告两种问题:警告和错误。警告只是表明您的代码可能无法正常工作,但它们不会阻止您的程序执行。错误可以是编译时或运行时。编译时错误会阻止代码执行; 运行时错误导致 代码执行时引发异常。

变量

这是创建变量并初始化它的示例:

var name = 'Bob';

变量存储引用。调用的变量name包含对String值为“Bob” 的对象的引用。

name推断变量的类型String,但您可以通过指定它来更改该类型。如果对象不限于单一类型,请按照设计指南指定Object或dynamic类型。

dynamic name = 'Bob' ;

另一种选择是显式声明可以推断出的类型:

String name = 'Bob' ;

默认值

未初始化的变量的初始值为null。即使是带有数字类型的变量最初也是null,因为数字也都是对象。

int lineCount ; assert (lineCount == null );

最终和常数

如果您从不打算更改变量,请使用final或const代替var或替代类型。最终变量只能设置一次; const变量是编译时常量。

以下是创建和设置最终变量的示例:

final name = 'Bob' ; //没有类型注释
final String nickname = 'Bobby' ;  

使用const为您要为变量的编译时间常数。如果const变量在类级别,请标记它static const。在声明变量的地方,将值设置为编译时常量,例如数字或字符串文字,const变量或常数上的算术运算结果:

const bar = 1000000; // Unit of pressure (dynes/cm2)
const double atm = 1.01325 * bar; // Standard atmosphere 

内置类型

  • numbers 数字
  • strings 字符串
  • booleans 布尔
  • lists 列表(也称为数组)
  • maps 映射
  • runes 符文(用于表示字符串中的Unicode字符)
  • symbols 符号

数字

两种形式:

int
整数值不大于64位,具体取决于平台。

double
64位(双精度)浮点数,由IEEE 754标准规定。

字符串

Dart字符串是一系列UTF-16代码单元。您可以使用单引号或双引号来创建字符串:

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

布尔

类型bool。只有两个对象具有bool类型:true和false,它们都是编译时常量。

// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);

// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);

// Check for null.
var unicorn;
assert(unicorn == null);

// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Lists

也许几乎每种编程语言中最常见的集合是数组或有序的对象组。在Dart中,数组是 List对象,因此大多数人只是将它们称为列表。

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

Maps

通常,映射是关联键和值的对象。键和值都可以是任何类型的对象。每个键只出现一次,但您可以多次使用相同的值。

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

Runes

在Dart中,符文是字符串的UTF-32代码点。

Unicode为世界上所有书写系统中使用的每个字母,数字和符号定义唯一的数值。由于Dart字符串是一系列UTF-16代码单元,因此在字符串中表示32位Unicode值需要特殊语法。

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}

Symbols

符号对象表示达特程序声明的操作者或标识符。您可能永远不需要使用符号,但它们对于按名称引用标识符的API非常有用,因为缩小会更改标识符名称而不会更改标识符符号。

要获取标识符的符号,请使用符号文字, #后面跟着标识符:

#radix
#bar

符号文字是编译时常量。

功能

Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function。 这意味着函数可以分配给变量或作为参数传递给其他函数。您也可以像调用函数一样调用Dart类的实例。

以下是实现函数的示例:

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

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

main()函数

每个应用程序都必须具有顶级main()功能,该功能用作应用程序的入口点。该main()函数返回void并具有List参数的可选参数。

以下main()是Web应用程序的功能示例:

void main() {
  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);
}

注意:..前面代码中 的语法称为级联。使用级联,您可以对单个对象的成员执行多个操作。

作为第一类对象的函数

您可以将函数作为参数传递给另一个函数。例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);

控制流程语句

您可以使用以下任一方法控制Dart代码的流程:

if 和 else
for 循环
while 和 do-while 循环
break 和 continue
switch 和 case
assert
也可以使用 try-catch 和影响控制流 throw,如异常中所述。

示例


if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

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

var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  case 'APPROVED':
    executeApproved();
    break;
  case 'DENIED':
    executeDenied();
    break;
  case 'OPEN':
    executeOpen();
    break;
  default:
    executeUnknown();
}

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}

Dart是一种面向对象的语言,具有类和基于mixin的继承。每个对象都是一个类的实例,所有类都来自Object。 基于Mixin的继承意味着虽然每个类(除了Object)只有一个超类,但是类体可以在多个类层次结构中重用。

class Point {
  num x; // Declare instance variable x, initially null.
  num y; // Declare y, initially null.
  num z = 0; // Declare z, initially 0.

  Point(num x, num y) {
    // There's a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }

  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }

  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;
    }
}

抽象类和方法

抽象方法
实例,getter和setter方法可以是抽象的,定义一个接口,但将其实现留给其他类。抽象方法只能存在于抽象类中。

抽象类
使用abstract修饰符定义抽象类 - 无法实例化的类。抽象类对于定义接口非常有用,通常还有一些实现。如果希望抽象类看起来是可实例化的,请定义工厂构造函数。

abstract class Doer {
  // Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // Provide an implementation, so the method is not abstract here...
  }
}

继承和实现

实现:

// 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 Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}

重写:

class SmartTelevision extends Television {
  @override
  void turnOn() {...}
  // ···
}

枚举类型

枚举类型(通常称为枚举或枚举)是一种特殊类,用于表示固定数量的常量值。

使用枚举
使用enum关键字声明枚举类型:

enum Color { red, green, blue }

静态类变量和方法

使用static关键字实现类范围的变量和方法。

静态变量:

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

静态方法:

import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

泛型

如果您查看基本数组类型的API文档 List,您会看到该类型实际上是List。<...>表示法将List标记为 通用(或参数化)类型 - 具有正式类型参数的类型。按照惯例,大多数类型变量都有单字母名称,例如E,T,S,K和V.

var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};

使用库

使用import指定如何从一个库中的命名空间在另一个库的范围内使用。

唯一需要的参数import是指定库的URI。对于内置库,URI具有特殊dart:方案。对于其他库,您可以使用文件系统路径或package: 方案。该package:方案指定由包管理器(如pub工具)提供的库。

import 'dart:html';
import 'package:test/test.dart';
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

异步支持

Dart库中包含许多返回Future或Stream对象的函数。这些函数是异步的:它们在设置可能耗时的操作(例如I/O)后返回,而不等待该操作完成。

处理Future

当您需要完成的Future的结果时,您有两个选择:

  • 使用async和await。
  • 使用Future API。

使用async和await异步的代码,但它看起来很像同步代码。

await lookUpVersion();
Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}

使用try,catch和finally 处理使用await以下代码的错误和清理:

try {
  version = await lookUpVersion();
} catch (e) {
  // React to inability to look up the version
}

声明异步函数

一个异步函数是一个函数体标有async修改。
将async关键字添加到函数使其返回Future。

Future<String> lookUpVersion() async => '1.0.0';

如果您的函数没有返回有用的值,请设置其返回类型Future<void>

处理Streams

当您需要从Stream获取值时,您有两个选择:

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

注意: 在使用之前await for,请确保它使代码更清晰,并且您确实希望等待所有流的结果。

await for (varOrType identifier in expression) {
  // Executes each time the stream emits a value.
}

Generators

当您需要延迟地生成一系列值时,请考虑使用生成器函数。Dart内置支持两种形式:

  • 同步生成器:返回一个Iterable对象。
  • 异步生成器:返回Stream对象。

要实现同步生成器函数,请将函数体标记为sync,并使用yield语句来传递值。
要实现异步生成器函数,请将函数体标记为async
,并使用yield语句来传递值。

Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}

Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}
posted @ 2019-01-17 15:33  S&L·chuck  阅读(4021)  评论(0编辑  收藏  举报