当前位置:   article > 正文

Flutter学习之Dart语言基础(关键字)_dart @internal

dart @internal

Flutter日渐火爆,因此在进行Flutter学习前先学习一些其所使用的开发语言dart的基础,这篇文章主要学习了

  1. Dart的基础代码示例
  2. Dart的概念
  3. Dart的关键字
Dart的基础代码示例
// 定义一个方法。
printInteger(int aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// main入口函数。
main() {
  var number = 42; // 声明并初始化变量。
  printInteger(number); // 函数调用。
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
// 注释

dart注释方法,更多注释可以看我的另一篇文章https://www.jianshu.com/p/d1dae0d5c472

int

数据类型,更多数据类型可看https://www.dartlang.org/guides/language/language-tour#built-in-types

print()

一种方便的显示输出方式

‘…’ (or “…”)

字符串,dart中更推荐使用**’…’**

$variableName (or ${expression})

字符串插值:包括字符串文字内部的变量或表达式的字符串

var

一种声明变量而不指定其类型的方法,关键字之一

Dart重要概念

当要学习dart时,请记住以下事实和概念:

  • 一切皆为对象,放在变量中的所有内容都是一个对象,每个对象都是一个class的实例,numbers,函数和null都是对象,所有对象都继承自Object类。下面给个图你看一下,没错,连int都是对象:
    int

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

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

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

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

  • 与Java不同,Dart没有关键字public,protected和private,如果标识符以下划线(_)开头,则它代表是私有的,否则都为公有。

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

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

关键字

dart共有60个关键字,所以以下篇幅可能有点长

abstract2dynamic2implements2show1
as2elseimport2static2
assertenuminsuper
async1export2in2super
await3extendsissync1
breakexternal2library2this
casefactory2mixin2throw
catchfalsenewtrue
classfinalnulltry
constfinallyon1typedef2
continueforoperator2var
covariant2Function2part2void
defaultget2rethrowwhile
deferred2hide1returnwith
doifset2yield3
  • 带有上标1的关键字是上下文关键字,仅在特定位置具有含义。
  • 带有上标2的关键字是内置标识符, 为了简化将JavaScript代码移植到Dart的任务,这些关键字在大多数地方都是有效的标识符,但它们不能用作类或类型名称,也不能用作导入前缀。
  • 带有上标3的关键字为新版本中的新标识符,是与Dart 1.0发布后添加的异步支持相关的有限保留字。

详细可看下面说明

abstract

使用abstract修饰符定义抽象类即无法实例化的类,抽象类可以自定义一些接口。抽象类通常有抽象方法,下面是一个声明具有抽象方法的抽象类的示例:

// 该类声明为抽象类且不可实例化。
abstract class AbstractContainer {
  // 定义构造函数,变量,方法等...

  // 其他....  

  // 抽象方法。
  void updateChildren(); 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

下面为实现抽象方法的例子:

//抽象类
abstract class Doer {
  void doSomething(); // 定义一个抽象方法
}

//继承抽象类实现抽象方法
class EffectiveDoer extends Doer {
  void doSomething() {
    // 实现逻辑
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
dynamic

顾名思义,dynamic(动态), 直接先上代码

void judge(dynamic arg){
    if (arg is bool){
      print('arg is bool');
    } else if (arg is String){
      print('arg is String');
    } else if (arg is int){
      print('arg is int');
    } else {
      print('arg is others');
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

dynamic同等于Object, 即上面代码可以等同于下面代码:

void judge(Object arg){
    if (arg is bool){
      print('arg is bool');
    } else if (arg is String){
      print('arg is String');
    } else if (arg is int){
      print('arg is int');
    } else {
      print('arg is others');
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在Dart中,dynamic和Object可表示所有类型, 这两者区别是使用dynamic可以处理更复杂的不确定类型,例如超出了Dart的类型系统,或者值来自互操作或者在静态类型系统范围之外的情况。

implements

Java中,该关键字用于实现接口类(interface), Dart中亦有相同的意思,实现接口,我们先看代码:

// Person类,包含方法greet().
class Person {
  //在该类中,属于私有,仅对当前类可见
  final _name;

  // 不是接口,只是构造函数
  Person(this._name);

  // 接口
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// 实现Person类接口的类
class Impostor implements Person {
  //只是一个普通的get方法,可忽略
  get _name => '';

  //实现Person的greet方法
  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')));  //打印 -> Hello, Bob. I am Kathy.
  print(greetBob(Impostor())); //打印 -> Hi Bob. Do you know who I am?
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Dart中没有Java的interface功能,如果Impostor在不继承Person类的情况想实现Person类的接口的话,可以使用implements关键字。implements可同时实现多个类的接口:

class Point implements Comparable, Location {...}
  • 1
show & hide

有时候我们导入一个库,如果只想使用库的一部分,则可以有选择地导入库,例如:

// 只导入foo
import 'package:lib1/lib1.dart' show foo;
  • 1
  • 2
//导入整个库除了foo
import 'package:lib2/lib2.dart' hide foo;
  • 1
  • 2
as, is, is!

as,is,和 !is 运算符在运行时检查类型很方便

  • as: 类型转换, 也用于指定库前缀
  • is: 类似于java的instanceof
  • !is: is操作符的取反, 即不是xxx

代码示例:

if (emp is Person) {
  // 类型检查
  emp.firstName = 'Bob';
}
  • 1
  • 2
  • 3
  • 4
// 如果emp为Person,则将firstName改为Bod, 否则会在运行时期报错
(emp as Person).firstName = 'Bob';
  • 1
  • 2

如果导入两个具有冲突标识符(class)的库,则可以为一个或两个库指定前缀。 例如,如果library1和library2都有一个Element类,那么as可以这样使用:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2; //指定库的前缀为lib2

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

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
if & else

与Java或其他语言一样,Dart支持带有可选else语句的if语句:

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
import

与Java一样,使用import导入其他包。例如,Dart Web应用程序通常使用dart:html库,可以这样导入:

import 'dart:html';
  • 1

如果只是想导入某个包下的某个dart文件,可以这样导入:

import 'package:test/test.dart'; //指定导入test.dart(类似于Java中的test.java)
  • 1
static

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

static变量(只有在使用的时候才会进行初始化):

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

void main() {
  assert(Queue.initialCapacity == 16);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

static方法:

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
assert

断言assert(条件);
如果条件为返回false,使用assert语句可以中断正常执行, 代码:

// text等于null时中断
assert(text != null);

// number > 100时中断
assert(number < 100);

// 如果urlString不是以"https"开头
assert(urlString.startsWith('https'));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果要附加一个消息到断言,可在第二个参数输入一个字符串:

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');
  • 1
  • 2
enum

枚举类型(通常称为枚举或枚举)是一种特殊类型,用于表示固定数量的常量值。
使用enum关键字声明枚举类型, 例如:

enum Color { red, green, blue }
  • 1

枚举中的每个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。 例如,第一个值具有索引0,第二个值具有索引1:

  print('red index: \${Color.red.index}'); // -> 打印red index: 0
  print('green index: \${Color.green.index}'); // -> 打印: green index: 1
  print('blue index: \${Color.blue.index}');· //-> 打印: blue index: 2
  • 1
  • 2
  • 3

要获取枚举中所有值的列表,可以使用以下方法:

List<Color> colors = Color.values;
  • 1

您可以在switch语句中使用枚举,如果您不处理所有枚举值,您将收到警告:

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // 没有这行代码的话,会有一个警告
    print(aColor); // 'Color.blue'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

枚举类型具有以下限制:

1.不能子类化,混合或实现枚举。
2.无法显式实例化枚举。

for & in

可以使用标准for循环进行迭代, 例如:

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

像List和Set这样的可迭代类支持使用的for-in形式迭代:

var list = [0, 1, 2];
  for (var x in list) {
    print(x); // 0 1 2
  }
  • 1
  • 2
  • 3
  • 4

等同于:

  for (int i = 0; i < list.length; i++){
    print(list[i]); // 0 1 2
  }
  • 1
  • 2
  • 3
extend & super

使用extends来继承一个类,使用super来调用父类:

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn(); //调用父类方法
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
async & await
  • async -> 异步
  • await -> 等待

Dart库中包含许多返回Future或Stream对象的函数,关于Future和Steam会在后续进行讲解,这里暂不深究。 这些函数是异步的:它们在设置可能耗时的操作(例如I/O)后返回,而不等待该操作完成。

async和await关键字用于异步编程

async关键字修饰一个方法,要求必须返回一个Future对象,下面为代码例子:

//async关键字声明该函数内部有代码需要延迟执行
Future<String> getResult() async { 
  return await getResultFromDb(); //await关键字声明运算为延迟执行,然后返回运算结果
}

Future<String> getResultFromDb() {
  // 很多延时操作
  // 很多延时操作
  // 很多延时操作
  // 很多延时操作
  return new Future((){
      return 'This is server...';
  });
}

//打印:result = This is server...
 print(getResult().then((result){
      print('result = $result');
  }));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
export

我们来看一个官方的http库的代码: http: ^0.12.0
export.png
我们可以看到该包下面有一个src目录,还有一些其他的dart文件,Dart库中,lib/src下的代码被认为是私有的, lib下的文件为对外公开即外部可以使用的,我们可以看到该http库下browser_client.dart, http.dart, io_client.dart, testing.dart是公开的API,我们拿其中一个,这里我们拿http.dart文件看看

export 'src/base_client.dart';
export 'src/base_request.dart';
export 'src/base_response.dart';
export 'src/byte_stream.dart';
export 'src/client.dart';
export 'src/exception.dart';
export 'src/multipart_file.dart';
export 'src/multipart_request.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/streamed_request.dart';
export 'src/streamed_response.dart';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看到export了几个文件,即导出了这几个文件,使外部这几个文件的api,这时我们导入http来使用一下:

import 'package:http/http.dart' as http;
  • 1

image.png

可以看到导入的几个文件的类都可用了,那我们再找一个没export的文件来看看外部是否可用,我们拿browser_client.dart来看看,其中有一个类:
client.png

我们在外部使用的时候:
error.png

是会报错的,因为该类并没有export,即外部不可使用。

interface

已移除

switch & case & default

Dart中的switch语句可使用整数,字符串或编译时常量, 以下为使用字符串代码示例:

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
sync & yield
  • sync 同步
  • yield 生成

当我们需要懒惰地(不需要很多手动定义可迭代类时复杂的公式化代码)生成一系列值时,可以考虑使用生成器函数, Dart内置支持两种生成器函数:

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

同步生成器:将函数体标记为sync *,并使用yield语句来赋值,下面例子为返回 0-n 的迭代器:

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

//使用
void main() {
  var it = naturalsTo(5).iterator;
  while(it.moveNext()) {
    print(it.current);
  }
}

//打印
start
value = 0
value = 1
value = 2
value = 3
value = 4
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

调用方法naturalsTo时,会马上返回Iterable,且可以获取迭代器iterator,但是,在调用遍历之前,naturalsTo函数主体并不会立即执行,这里我们可以看到调用var it = naturalsTo(5).iterator的时候没有任何打印,并且我们可以看到,在遍历打印的时候,先调用start,当把所有值打印完了,再打印end。说明调用naturalsTo得到这个Iterable的iterator的时候,yield会在你每次调用moveNext进行遍历的时候产生一个值。当函数运行到yield的时候,yield这里声明一个求值表达式,返回值后,函数会在下一次moveNext的时候继续执行函数体。

异步生成器函数,将函数体标记为async *,并使用yield语句来传递值:

Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}

//使用
void main() {
  asynchronousNaturalsTo(5).listen((v) {
    print(v);
  });
}

//打印
start
0
1
2
3
4
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

使用异步生成器返回数据流string,和sync*一样,调用asynchronousNaturalsTo会立即返回Stream,但是只有在listen监听数据流的时候才会调用asynchronousNaturalsTo函数体,并且通过yield声明求值表达式来计算对应的值。

如果生成器内部使用递归的话,可以使用yield *来提高其性能:

Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}

//使用
void main() {
  print(naturalsDownFrom(5));
}

//打印
(5, 4, 3, 2, 1)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

naturalsDownFrom函数还是返回一个Iterable,当参数为5时,5 > 0时,先执行yield 5, 这时迭代器首先会产生一个值5,然后再通过yield*生成新的值,并且加到当前迭代器中。

break & continue

跳出循环

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}
  • 1
  • 2
  • 3
  • 4

跳到下一个循环迭代

or (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
external

表示代码的实现由外部提供,我们定义一个类:

class Object {
  const Object();

  external bool operator ==(other);
  external int get hashCode;
  external String toString();
}

//使用
void main() {
  Object object = new Object();
  print('to string = ${object.toString()}');
}

//打印
to string = null
//但是如果我们将toString去掉的话,则会打印
to string = Instance of 'Object' //dart中默认的toString打印
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

external声明了这些方法需要由外部去实现,若外部没实现,则会返回null

library & part

使用library关键字可以定义一个库的名字,我们这里自定义一个库来说明一下这两个关键字:
library.png
这里分别有3个文件,我们看看:
main.dart

library main; //定义当前库的名字为main
import 'dart:math' as math; 

//声明以下两个文件属于main库
part 'test/lib/liba.dart'; 
part 'test/lib/libb.dart';

class LibMain{
    static int max(int a, int b) => math.max(a, b);

    static String getParts() => LibA.TAG + ", " + LibB.TAG;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

liba.dart

part of main;  //声明属于main库

class LibA{
  static String TAG = 'liba';
}
  • 1
  • 2
  • 3
  • 4
  • 5

libb.dart

part of main; //声明属于main库

class LibB{
  static String TAG = 'libb';
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

再导入main之后,

import 'lib/main.dart';
  • 1

liba.dart和libb.dart中声明的类外部可用:
library.png

part可以将库拆分为多个Dart文件,但是建议尽量避免使用其来创建库,因为这样会使代码很难阅读和修改。建议直接直接在lib/<包名> .dart下创建一个“main”库文件,用一个main文件来管理所有公共API。

this

和Java中this相类似,用this关键字来引用当前实例

factory

用来修饰构造函数,描述该构造函数作为一个工厂构造函数功能,在实现不用总是创建新实例的构造函数的时候,可以使用factory关键字,例如下面例子中,可能从缓存中返回实例,或者子类的实例。

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

  //一个维护Logger类的map
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  //根据不同的name获取对应的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);
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

注意,使用factory修饰的构造函数不能使用this,类似于在Java的static函数中,不能使用this

mixin & with & on

Dart 2.1中引入了对mixin关键字的支持, 我们可以看到官方的描述:Mixins是一种在多个类层次结构中重用类代码的方法。关键信息:

  • 多个类层次结构
  • 重用类代码

我这里只简单描述下该关键字的作用和使用方法:

  • mixin字面意思为混入的意思,要使用mixin的话,需要使用with关键字,后跟一个或多个mixin的名称, 可视为混入多个类
  • 有时候我们需要创建一个类,这个类需要使用不同类的不同的方法的时候,就需要使用mixin方法,,因为Dart中只能继承一个类,而且使用接口的话,必须在其他类也实现这个接口,下面我们使用我们看下下面的例子:
//程序员喜欢写代码
class Programmer{
  code(){
    print('I am a programmer, i like coding.');
  }
}

//歌唱家喜欢唱歌
class Singer{
  singing(){
    print('I am a singer, i like singing.');
  }
}

//既爱编码,也爱唱歌
class Mixin with Programmer, Singer{

}

void main() {
  Mixin mixin = Mixin();
  mixin.code();
  mixin.singing();
}

//打印:
I am a programmer, i like coding.
I am a musician, i like singing.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

注意:这里类Programmer和Singer不能声明构造函数包括命名函数:
mixin.png

当我们使用mixin调用不同类相同接口结果会是怎样呢,我们看下面代码:

class A {
  name(){
    print('I am a student.');
  }
}

class B{
  name(){
    print('I am a teacher.');
  }
}

class AB with A, B{

}

class BA with B, A{

}

void main() {
  new AB().name();

  new BA().name();
}

//打印:
I am a teacher.
I am a student.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

可以看到接口相同的情况这里是name,最终会调用with的最后一个类的接口。

如果我们需要限定,什么类才能被混入,可以使用mixin+on的方法限定:

//mixn定义了类Flutter要求只有实现Programmer类的才能被混入
mixin Flutter on Programmer{
  flu(){
    print('This is in flutter.');
  }
}

//会如下面图片报错
//class A  with Flutter{
//}

//可以混入
class B extends Programmer with Flutter{
}

new B ().flu();  //打印This is in flutter.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

mixin.png

最后,关于mixin更详细的解释可以参考:

throw

抛出异常:

throw FormatException('Expected at least 1 section');
  • 1

throw.png

也可以抛出任何任意对象异常:

throw 'Out of llamas!';
  • 1

throw.png

class Throw{
  @override
  String toString() {
    return 'Are you ok?';
  }
}

void main() {
  throw new Throw();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

throw.png

try & catch & finally & on & rethrow

异常捕获:

//普通使用
void main() {
  try{
    throw "You are wrong.";
  }catch (e){
    print('catch exception: '+e);
  }
}

//打印:
catch exception: You are wrong.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用on可以捕获某种异常

class ExceptionA{
  @override
  String toString() {
    return 'This is exception a.';
  }
}

class ExceptionB{
  @override
  String toString() {
    return 'This is exception b.';
  }
}

throwCatchException(Object object){
  try{
    throw object;
  } on ExceptionA{ //指定某种异常类
    print("It's exception a.");
  } on ExceptionB catch(e){  //指定某种异常类并获取异常对象
    print(e);
  } on Exception catch (e){
    print(e);
  }
}

void main() {
  throwCatchException(new ExceptionA());
  throwCatchException(new ExceptionB());
  throwCatchException(new Exception(''));
}
//打印:
It's exception a.
This is exception b.
Exception: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

可以为catch()指定一个或两个参数, 第一个是抛出的异常对象,第二个是堆栈跟踪(StackTrace对象):

void main() {
  try{
    throw 'This is a exception.';
  }catch (e, s){
    print('e ${e}');
    print('s ${s}');
  }
}
//打印:
e This is a exception.
s #0      main (file:///E:/flutter/projects/flutter/test/test.dart:5:5)
#1      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#2      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果想异常可传播, 使用rethrow接口

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // 运行时出错
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow;  //允许调用者可以看到异常
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}
//打印:
misbehave() partially handled NoSuchMethodError.
main() finished handling NoSuchMethodError.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

无论是否抛出异常,要确保某些代码运行,请使用finally子句。 如果没有catch子句与异常匹配,则在finally子句运行后抛出异常:

class ExceptionA{
  @override
  String toString() {
    return 'This is exception a.';
  }
}

class ExceptionB{
  @override
  String toString() {
    return 'This is exception b.';
  }
}

finallyMethod(){
  print('finally method.');
}

void main() {
  try {
    throw new ExceptionA();
  } on ExceptionB catch (e) {
    print(e);
  } finally{
    finallyMethod();
  }
}

//打印:
finally method.
Unhandled exception:
This is exception a.
#0      main (file:///E:/flutter/projects/flutter/test/test.dart:21:5)
#1      _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#2      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
false & true

为了表示布尔值,Dart有一个名为bool的类型, 只有两个对象具有bool类型: true和false,它们都是编译时常量

new

创建类实例

class

声明一个类

final & const

final声明一个变量只能初始化一次,和java用法相同

const声明一个是编译时常量的变量, 常量变量不能进行赋值,如果const变量在类级别,则将其标记为static const。
当我们想让一个变量不被改变,可以声明为const变量。

typedef

typedef用于给函数类型指定名称,因为在Dart中,函数也是一个对象,通常用Function泛指所有函数,我们来看一下下面的例子(没有使用函数别名):


class SortedCollection {
  Function compare;
  
  //这里需要传递一个返回值为int,参数为(Object, Object)的函数
  SortedCollection(int f(Object a, Object b)) {
    compare = f;
  }
}

//一个返回值为int,参数为(Object, Object)的函数
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);

  // 我们都知道compare是一个函数
  // 但是我们知道它是什么类型的函数吗,意味着我们只知道它是一个函数,但是是什么类型的函数我们不知道
  assert(coll.compare is Function); // 这里毫无疑问是true, 即不会中断执行
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我们可以用typedef来声明一个函数类型:

 //定义一个函数类型为compare,其类型为
typedef Compare = int Function(Object a, Object b);

class SortedCollection {
  Compare compare;

  SortedCollection(this.compare);
}

//一个返回值为int,参数为(Object, Object)的函数即类型为Compare的函数
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);
  assert(coll.compare is Function);  //True
  assert(coll.compare is Compare); //True
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

目前typedef只能用于声明函数类型,

operator

如果你想定义一个Vector类(向量类),可以使用以下运算符:

<+|[]
>/^[]=
<=~/&~
>=*<<==
-%>>

下面为一个覆盖+和 - 运算符的类的示例:

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

// Operator == and hashCode not shown. For details, see note below.
// ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 3);
  final vw = v + w;
  final ww = v - w;

  print('vw -> (${vw.x}, ${vw.y})');
  print('ww -> (${ww.x}, ${ww.y})');
}

//打印:
vw -> (4, 6)
ww -> (0, 0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
var

使用var声明一个变量但是不指定其类型

var name = 'Bob'; //声明一个变量为字符串变量
  • 1

但是一旦声明赋值了为一个类型候,不能再分配给另一个类型
var.png

covariant

我们在继承一个类的时候,在重构一个方法时,强制将其参数由父类缩窄成其子类的话,会提示错误,例子:

//定义一个Animal类,其函数chase参数为Animal
class Animal {
  void chase(Animal x) {}
}

class Mouse extends Animal {
  getName(){
    return 'mouse';
  }
}

class Cat extends Animal {
  //强制将chase函数的Animal参数缩窄成Mouse 

  void chase(Mouse mouse) {
    print('cat chase ${mouse.getName()}');
  }
}

//报错, 提示重写类型不匹配
test/test.dart:12:20: Error: The parameter 'mouse' of the method 'Cat::chase' has type #lib1::Mouse, which does not match the corresponding type in the overridden method (#lib1::Animal).
Change to a supertype of #lib1::Animal (or, for a covariant parameter, a subtype).
  void chase(Mouse mouse) {
                   ^
test/test.dart:2:8: Context: This is the overridden method ('chase').
  void chase(Animal x) {}
       ^
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

使用covariant关键字后:

class Animal {
  void chase(Animal x) {}
}

class Mouse extends Animal {
  getName(){
    return 'mouse';
  }
}

class Cat extends Animal {
  void chase(covariant Mouse mouse) {
    print('cat chase ${mouse.getName()}');
  }
}

void main(){
  new Cat().chase(new Mouse());
}
//打印
cat chase mouse
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

covariant字义为协变,即我和编译器协商,这个参数缩窄变化是我故意这样做的,你别抛异常了。

Function

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

//定义一个add函数
int add(int a, int b) => a+b;

handle(Function function){
  print('handle: ${function(1, 2)}'); //打印function的结果
}

void main(){
  handle(add); //调用handle并传递add函数
}
//打印
handle: 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
void

在Dart 1中,void仅可用作函数的返回类型(例如void main()),但在Dart 2中它已被推广,并且可在其他地方使用, 例如Future

void类型不能用于任何东西,且将某些东西分配给void类型是无效的:

void foo() {}
void main() {
  var bar = foo(); // 无效
}
  • 1
  • 2
  • 3
  • 4

The expression here has a type of ‘void’, and therefore cannot be used. -> 此表达式的类型为“void”,无法使用
void.png

在函数中,表示该函数无需返回值。

在实践中,一般使用void来表示“任何我不关心元素”,或者更常见的是,表示“省略”,例如在Future 或Stream 中。

get & set

在Java中,getter和setter应该是蛮令我们头疼,如果一些类的属性足够多的话,提供getter和setter接口后,文件很轻松可以达到成千上百行。但是在Dart中,提供了set和get关键子来提供对象属性的读写访问权限。

class Rectangle {
  num left, top, width, height;

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

  //定义两个可计算的属性right 和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;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  
  print('right: ${rect.right}');
  rect.right = 100;
  print('right: ${rect.right}');

  print('bottom: ${rect.bottom}');
  rect.bottom = 120;
  print('bottom: ${rect.bottom}');
}

//打印:
right: 23
right: 100
bottom: 19
bottom: 120
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

在Dart中,使用get和set实现getter和setter功能,是不是简洁多了呢

使用get和set后,我们可以从实例变量开始,在get/set的方法中用方法封装,而无需更改外部调用的代码。

while & do while

while: 在循环执行之前计算条件

while (!isDone()) {
  doSomething();
}
  • 1
  • 2
  • 3

do-while: 在循环开始执行后计算条件

do {
  printLine();
} while (!atEndOfPage());
  • 1
  • 2
  • 3
deferred

deferred用于声明一个延迟加载一个库,通常叫懒加载。允许你只有在需要使用该库的时候,再加载该库。

//文件calculate.dart
class Calculate{

  static String name = "Cal";

  static printf(String s){
    print('cal: $s');
  }

  int add(int a, int b) => a + b;
}

//文件test.dart
import 'calculate.dart' deferred as cal; //声明该库会延迟加载且命名为cal

void main() {
  print('1');
  greet();
  print('2');
  print('3');
}

//异步加载库calculate.dart
//加载完毕后再进行操作
Future greet() async {
  await cal.loadLibrary();
  print('cal name: ${cal.Calculate.name}');
  print('add(1, 2) = ${new cal.Calculate().add(1, 2)}');
  cal.Calculate.printf('ss');
}

//打印:
1
2
3
cal name: Cal
add(1, 2) = 3
cal: ss
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
return

用于在函数中返回一个值

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号