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

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

  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); // 函数调用。
}
复制代码
// 注释

dart注释方法,更多注释能够看个人另外一篇文章https://www.jianshu.com/p/d1dae0d5c472java

int

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

print()

一种方便的显示输出方式express

'...' (or "...")

字符串,dart中更推荐使用**'...'**编程

$variableName (or ${expression})

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

var

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

Dart重要概念

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

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

    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个关键字,因此如下篇幅可能有点长

abstract2 dynamic2 implements2 show1
as2 else import2 static2
assert enum in super
async1 export2 in2 super
await3 extends is sync1
break external2 library2 this
case factory2 mixin2 throw
catch false new true
class final null try
const finally on1 typedef2
continue for operator2 var
covariant2 Function2 part2 void
default get2 rethrow while
deferred2 hide1 return with
do if set2 yield3
  • 带有上标1的关键字是上下文关键字,仅在特定位置具备含义。
  • 带有上标2的关键字是内置标识符, 为了简化将JavaScript代码移植到Dart的任务,这些关键字在大多数地方都是有效的标识符,但它们不能用做类或类型名称,也不能用做导入前缀。
  • 带有上标3的关键字为新版本中的新标识符,是与Dart 1.0发布后添加的异步支持相关的有限保留字。

详细可看下面说明

abstract

使用abstract修饰符定义抽象类即没法实例化的类,抽象类能够自定义一些接口。抽象类一般有抽象方法,下面是一个声明具备抽象方法的抽象类的示例:

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

  // 其余....  

  // 抽象方法。
  void updateChildren(); 
}
复制代码

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

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

//继承抽象类实现抽象方法
class EffectiveDoer extends Doer {
  void doSomething() {
    // 实现逻辑
  }
}
复制代码
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');
    }
}
复制代码

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');
    }
}
复制代码

在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?
}
复制代码

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

class Point implements Comparable, Location {...}
复制代码
show & hide

有时候咱们导入一个库,若是只想使用库的一部分,则能够有选择地导入库,例如:

// 只导入foo
import 'package:lib1/lib1.dart' show foo;
复制代码
//导入整个库除了foo
import 'package:lib2/lib2.dart' hide foo;
复制代码
as, is, is!

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

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

代码示例:

if (emp is Person) {
  // 类型检查
  emp.firstName = 'Bob';
}
复制代码
// 若是emp为Person,则将firstName改成Bod, 不然会在运行时期报错
(emp as Person).firstName = 'Bob';
复制代码

若是导入两个具备冲突标识符(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();
复制代码
if & else

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

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
复制代码
import

与Java同样,使用import导入其余包。例如,Dart Web应用程序一般使用dart:html库,能够这样导入:

import 'dart:html';
复制代码

若是只是想导入某个包下的某个dart文件,能够这样导入:

import 'package:test/test.dart'; //指定导入test.dart(相似于Java中的test.java)
复制代码
static

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

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

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

void main() {
  assert(Queue.initialCapacity == 16);
}
复制代码

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);
}
复制代码
assert

断言assert(条件); 若是条件为返回false,使用assert语句能够中断正常执行, 代码:

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

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

// 若是urlString不是以"https"开头
assert(urlString.startsWith('https'));
复制代码

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

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');
复制代码
enum

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

enum Color { red, green, blue }
复制代码

枚举中的每一个值都有一个索引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
复制代码

要获取枚举中全部值的列表,可使用如下方法:

List<Color> colors = Color.values;
复制代码

您能够在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.没法显式实例化枚举。

for & in

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

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

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

var list = [0, 1, 2];
  for (var x in list) {
    print(x); // 0 1 2
  }
复制代码

等同于:

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

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

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

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn(); //调用父类方法
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}
复制代码
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');
  }));
复制代码
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';
复制代码

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

import 'package:http/http.dart' as http;
复制代码

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();
}
复制代码
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
复制代码

调用方法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
复制代码

使用异步生成器返回数据流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)

复制代码

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

break & continue

跳出循环

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}
复制代码

跳到下一个循环迭代

or (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}
复制代码
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打印
复制代码

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;
}
复制代码

liba.dart

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

class LibA{
  static String TAG = 'liba';
}
复制代码

libb.dart

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

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

复制代码

再导入main以后,

import 'lib/main.dart';
复制代码

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

复制代码

注意,使用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.
复制代码

注意:这里类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.
复制代码

能够看到接口相同的状况这里是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.
复制代码

mixin.png

最后,关于mixin更详细的解释能够参考:

throw

抛出异常:

throw FormatException('Expected at least 1 section');
复制代码

throw.png

也能够抛出任何任意对象异常:

throw 'Out of llamas!';
复制代码

throw.png

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

void main() {
  throw new Throw();
}
复制代码

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.
复制代码

使用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: 复制代码

能够为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)
复制代码

若是想异常可传播, 使用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.
复制代码

不管是否抛出异常,要确保某些代码运行,请使用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)
复制代码
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, 即不会中断执行
}
复制代码

咱们能够用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
}
复制代码

目前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)
复制代码
var

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

var name = 'Bob'; //声明一个变量为字符串变量
复制代码

可是一旦声明赋值了为一个类型候,不能再分配给另外一个类型

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) {}
       ^
复制代码

使用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
复制代码

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
复制代码
void

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

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

void foo() {}
void main() {
  var bar = foo(); // 无效
}
复制代码

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
复制代码

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

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

while & do while

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

while (!isDone()) {
  doSomething();
}
复制代码

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

do {
  printLine();
} while (!atEndOfPage());
复制代码
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
复制代码
return

用于在函数中返回一个值

相关文章
相关标签/搜索