Dart 语言基础

转自—《Flutter:从入门到实践》http://gitbook.cn/m/mazi/comp/column?columnId=5cc01cc115a1a10d8cec9e86&utm_source=Raysd001
转载试读章节,已获得作者授权。


学习一门编程语言,首先要了解它的历史和特点。Dart 是 Google 公司推出的编程语言,于 2011 年就已经亮相了。Dart 也是一门面向对象的语言,语法和 Java、C、JavaScript 很像。所以会 Java 语言,学习 Dart 一般会快一些。

Dart 里所有的类都可以看成是对象,是单继承,动态类语言。可以进行多平台开发,我们的主角 Flutter 就是基于 Dart 语言编写的。这样我们就开始进行 Dart 语言的基础语法学习。本文将主要介绍:

  • Dart 的特点及简单介绍
  • Dart 的数据类型、操作符、变量常量
  • Dart 的运算符、流程控制语句
  • Dart 的函数(方法)、类
  • Dart 的泛型、接口等

1 Dart 简单介绍

1.1 为什么要介绍 Dart?

Google 计划未来的 Flutter 将会是移动应用、Web 应用、PC 应用等平台的跨平台高性能框架,也是未来的 Fuchsia 操作系统的主要框架,而 Flutter 是基于 Dart 编程语言编写的一个跨平台框架,所以一些语法是基于 Dart 语法来使用的,学习 Flutter 就要先了解 Dart。

1.2 什么是 Dart?

简单介绍下 Dart 语言。

Dart 是 Google 公司推出的编程语言,属于应用层编程语言,于 2011 年就已经亮相了。Dart 也是一门面向对象的语言,语法和 Java、C、JavaScript 很像。Dart 里所有的类都可以看成是对象,是单继承,动态类语言。Dart 可以进行移动应用、Web应用、服务器应用、PC 应用、物联网应用的开发等等,还在不断拓展开发平台,所以可以说 Dart 在各个平台领域“无所不能”。我们的主角 Flutter 就是基于 Dart 语言编写的。

Dart 语言基础_第1张图片
Dart的应用

1.3 Dart 的特性

接下来看下 Dart 的特性。

  • 语法简单明了,开发速度快、效率高,学习成本低。
  • 简单但是功能强大,可以开发 Web、移动端、PC、服务器端、物联网等平台应用。
  • 编译执行速度快,拥有自己的 Dart VM,在移动端和 Web 上拥有高性能。
  • 全平台语言,可移植。Dart 类似于中间件语言,可以编译成不同平台的原生代码,可以很方便地扩展成跨平台应用语言,如 Android 和 iOS 平台。
  • 语言的结构融合了 Java、C、JavaScrpit 的特点,并结合 React 响应式编程的思维规范进行构建的一个现代化编程语言。

1.4 Dart 的语法特点

  • 面向对象的语言,一切数据类型、API 都是对象,都继承自 Object 类;
  • 强类型语言,同时也是动态类型语言。对不确定类型的可以定义成一个动态类型;
  • Dart 没有设置定义访问域的关键字,如果某个变量或者方法、类的名称以"_"开头,说明这个变量或者方法、类是私有的,外部不可以调用使用;
  • Dart 有入口函数:main(){...};类似于Java的public void main(String[] args){...};
  • Dart 吸收了很多现代编程语言的特点,加入了很多便捷的语法支持,可以明显缩减代码量和提高可读性;
  • 拥有 Future 和 Streams 使用方式,可以进行类似 RxJava 式的使用。

2 Dart 的关键字

好了,说了这么多,接下来该进入正题,我们来学习一些具体知识。
首先看下 Dart 的关键字(33 个保留字,17 个内置标志符)。

33 个 Dart 保留字:

关键字
assert break const continue case catch class
default else enum extends final finally false
for is in new rethrow return superdo
switch throw try typedef this true var
void while with typedef this

17 个 Dart 内置标志符:

关键字
abstract as covariant deferred dynamic export external
factory get implements import library operator part
set static typedef

6 个 Dart2 新增异步功能关键字:

关键字
async async* await sync* yield yield*

25 个 Dart 特有关键字(和 Java 语言相比):

关键字
as assert async async* await const covariant
deferred dynamic export external factory get in
is library operator part rethrow set sync*
typedef var yield yield*

3 Dart 的数据类型

我们先看一个官方给的最基础的 Dart 例子,例如我们新建一个 demo.dart 类:

// 这是程序执行的入口
main() {
  var number = 30; // 定义变量number并进行赋值初始化
  printNumber(number); // 调用方法
}

// 定义方法printNumber
printNumber(num aNumber) {
  print('The number is $aNumber.'); // 在控制台打印输出内容
}

这个例子涵盖了 Dart 的一个基础的语法结构,有入口、有变量声明、赋值、定义方法、调用方法、传递参数、数据类型、变量引用等等。

那么接下来我们看下 Dart 支持的几种基本数据类型:numbers(num)、String、bool、List 集合、Map 集合、runes(用于在字符串中表示 Unicode 字符)、symbol。

numbers(num)类型是表示数值型的数据类型,包括 int 和 double 类型两种。num 是 int 和 double 类型的父类。其中 int 整数值一般范围在 -2^53 和 2^53 之间;double 是 64 位双精度浮点型数据类型。举个例子:

void main() {
  //定义int和double类型
  int a = 6;
  double b = 3.18;
  print('$a ,$b');

  // String转int
  int twoInt = int.parse('2');
  // String转double
  var twoDouble = double.parse('2.2');
  print('$twoInt ,$twoDouble');

  // int转String
  String intToString = 2.toString();
  // double转String,后面需加入保留小数点位数
  String doubleToString = 3.23456.toStringAsFixed(2);
  print('$intToString,$doubleToString');

  //自动四舍五入
  String fiveString = 2.12832.toStringAsFixed(2);
  print(fiveString);
}

输出结果为:

6 ,3.18
2 ,2.2
2,3.23
2.13

大家可以在 DartPad 上进行操作:https://dartpad.dartlang.org

String 类型

大家应该都很熟悉,字符串类型。

  • Dart 字符串是 UTF-16 编码的字符序列,可以使用单引号或者双引号来创建字符串。
  • 可以在字符串中使用表达式,用法是这样的: ${expression}。
  • 可以使用 + 操作符来把多个字符串链接为一个,当然也可以不用加号,多个带引号的字符串挨着写就可以了。
  • 使用三个单引号或者双引号也可以创建多行字符串。
  • 使用 r 前缀可以创建一个原始字符串。

再来看一个例子:

void main() {
  //单引号和双引号定义
  String singleString = 'A singleString';
  String doubleString = "A doubleString";
  print('$singleString ,$doubleString');

//使用$字符引用变量,使用{}引入表达式
  String userS = 'It\'s $singleString';
  String userExpression = 'It\'s expression,${singleString.toUpperCase()}';
  print('$userS');
  print('$userExpression');

//使用引号字符串邻接来拼接或者使用+号连接字符串
  String stringLines =
      'String ' 'concatenation' " works even over line breaks.";
  String addString = 'A and ' + 'B';
  print('$stringLines');
  print('$addString');

//使用三个引号(单引号或双引号)来创建多行字符串
  String s3 = '''
You can create
multi-line strings like this one.
''';
  String s33 = """This is also a
multi-line string.""";
  print('$s3');
  print('$s33');

//使用r为开头,显示定义一个原始字符串
  String s = r"It is a \n raw string.";
  print('$s');
}

输出结果为:

A singleString ,A doubleString
It's A singleString
It's expression,A SINGLESTRING
String concatenation works even over line breaks.
A and B
You can create
multi-line strings like this one.

This is also a
multi-line string.
It is a \n raw string.

bool 类型

用于定义 true 或 false 的数据类型,很简单。需要区别注意的是有些写法在 Dart 里不支持。

var name = 'Tom';
if (name) {
  // JavaScript可以这样写,Dart不行
  print('He is Tom!');
}

// JavaScript可以这样写,Dart不行
if (1) {
  print('A line Data.');
} else {
  print('A good Data.');
}

List 集合

Dart 里使用 List 来表示数据集合结构。

void main() {
  //定义初始化一个集合
  var list = [1, 2, 3];
  List listData = [5, 6, 7];
  print(list.length);
  print(list[0]);
  //集合数据赋值
  listData[1] = 8;
  print(listData[1]);
  //如果在集合前加了const关键字,集合数据不可以进行操作
  var constantList = const [1, 2, 3];
  List datas = List();
  datas.add('data1');
  datas.addAll(['data2', 'data3', 'data4', 'data5', 'data6']);
  //输出第一个元素
  print(datas.first);
  // 获取最后一个元素
  print(datas.last);
  // 获取元素的位置
  print(datas.indexOf('data1'));
  // 删除指定位置元素
  print(datas.removeAt(2));
  //删除元素
  datas.remove('data1');
  //删除最后一个元素
  datas.removeLast();
  // 删除指定范围元素,含头不含尾
  datas.removeRange(0, 2);
  //删除指定条件的元素
  datas.removeWhere((item) => item.length > 3);
  // 删除所有的元素
  datas.clear();
  //其他方法可以自己尝试
}

Map 集合

Map 集合存储数据特点就是键值对(key-value)形式。key 是唯一的,value 允许重复。看一个实例:

void main() {
  //定义一个map并赋值
  var gifts = {
    // Keys      Values
    'first': 'dog',
    'second': 'cat',
    'fifth': 'orange'
  };

  var nobleGases = {
    // Keys  Values
    2: 'a',
    10: 'b',
    18: 'b',
  };
  //定义一个map并赋值
  Map map = Map();
  map['first'] = 'a-value';
  map['second'] = 'b-value';
  map['fifth'] = 'c-value';
  Map nobleGasesMap = Map();
  nobleGasesMap[2] = 'a-value';
  nobleGasesMap[10] = 'b-value';
  nobleGasesMap[18] = 'c-value';
  //指定键值对类型
  var nobleGases = new Map();
  //获取某个key的value
  print(map['first']);
  //获取map大小
  print(map.length);
  //定义一个不可变的map
  final constantMap = const {
    2: 'a',
    10: 'b',
    18: 'c',
  };
  //其他API用法和List类似
}

Runes 类型

表示字符串 Unicode 编码字符(UTF-32 code points)等。

void 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 类型

使用 Symbol 字面量来获取标识符的 symbol 对象,也就是在标识符前面添加一个 # 符号。

 //看一个官方例子
 #radix
 #bar

4 Dart的操作符

看下 Dart 的操作符:

描述 操作符
一元后缀符(unary postfix) expr++   expr--   ()   []   .   ?.
一元前缀符(unary postfix) -expr   !expr   ~expr   ++expr   --expr
乘法类型(multiplicative) *   /   %   ~/
加法类型(additive) +   -
位操作符(shift) <<   >>
按位与(bitwise AND) &
按位异或(bitwise XOR) ^
按为或(bitwise OR) |
比较和类型测试(relational and type test) >=   >   <=   <   as   is   is!
等价(equality) ==   !=
逻辑与(logical AND) &&
逻辑或(logical OR) ||
是否是空(if null) ??
条件运算符(conditional) expr1 ? expr2 : expr3
级联运算符(cascade) ..
赋值(assignment) =   *=   /=   ~/=   %=   +=   -=   <<=   >>=   &=   ^=  

这些操作符用法和其他语言的含义和用法大同小异。

5 Dart 的流程控制语句

Dart 流程控制语句也不多,比较简单。主要有:

  • if 和 else
  • for 循环
  • while 和 do-while 循环
  • break 和 continue
  • switch 和 case
  • assert 断言(判断是否相等)

如果其中涉及到使用 try-catch 和 throw,可能会影响一些流程控制的跳转。

void main() {
  //if和else
  if (hasData()) {
    print("hasData");
  } else if (hasString()) {
    print("hasString");
  } else {
    print("noStringData");
  }

  //for循环
  var message = new StringBuffer("Dart is good");
  for (var i = 0; i < 6; i++) {
    message.write(',');
  }

  //while
  while (okString()) {
    print('ok');
  }
//do-while
  do {
    print('okDo');
  } while (!hasData());

  //break和continue
  while (true) {
    if (noData()) {
      break;
    }
    if (hasData()) {
      continue;
    }
    doSomething();
  }

  //switch和case
  var command = 'OPEN';
  switch (command) {
    case 'A':
      executeA();
      break;
    case 'B':
      executeB();
      break;
    case 'C':
      executeC();
      break;
    default:
      executeUnknown();
  }

  //Assert(断言)
  assert(string != null);
  assert(number < 80);
  assert(urlString.startsWith('https'));
}

Exceptions 异常捕获处理。

使用 throw 抛出异常。

throw new FormatException('Expected at least 2 section');

也可以抛出其他类型对象。

throw 'no data!';

使用 catch 捕获异常。

try {
  getData();
} on OutOfLlamasException {
  sendData();
} on Exception catch (e) {
  print('Unknown data Exception: $e');
} catch (e) {
  print('Some Exception really unknown: $e');
}

使用 rethrow 可以把捕获的异常给重新抛出。

//给出一个官方例子
final foo = '';

void misbehave() {
  try {
    foo = "You can't change a final variable's value.";
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // rethrow重新抛出,允许main()里的函数继续捕获处理异常
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

Finally 处理,和 Java 里的类似,不管是否出现异常,最终都要执行的方法写在这里。

try {
  getData();
} catch(e) {
  print('Error: $e');
} finally {
  //始终执行
  sendData();
}

6 Dart 的类和函数(方法)

类这个概念是面向对象里的,Dart 也依然保留。我们创建对象需要创建类对象,可以使用 new 关键字,也可以不使用:

var map=Map();
var map2=new Map();

调用类方法:

var map=Map();
  map.length;
  //通过 对象.方法 的形式来调用使用方法

使用 ?. 来替代 . 可以避免当左边对象为 null 时抛出异常:

  a?.name = 'Tom';

关于获取对象的类型,可以使用 Object 的 runtimeType 属性来获取实例的类型。

先看一个实例化对象,并获取和调用属性和方法的例子,和 Java 用法基本一致:

class Position {
  num x;
  num y;
  methodPosition(){
      ...
  }
}

void main() {
  var pos = new Position();
  pos.x = 5;//赋值
  print(pos.x);//取值
  pos.methodPosition();//调用方法
}

定义同名构造方法:

class Position {
  num x;
  num y;

  Position(num x, num y) {
    this.x = x;
    this.y = y;
  }
}
//也可以这样简化定义构造方法
class Point {
  num x;
  num y;

  Point(this.x, this.y);
}


注意:Dart 的构造函数不可以继承,父类的构造函数也不可以继承。

Dart 也支持抽象函数(抽象类):

abstract class Dog {
  //可以定义变量和抽象方法

  void doSomething(); // 定义抽象方法
}

class GoodDog extends Dog {
  void doSomething() {
    //实现逻辑
  }
}

Dart 的类可以继承多个类,这个 Dart 的一大特点。Dart 也支持实现多个接口,使用 implements 关键字:

class Comparable {
  final _name;

  Comparable(this._name);

  String good1(who) => 'Hello';
}

class Location {
  Location();

  String good2() => 'World!';
}

class ImlClass implements Comparable, Location {
  // ...
}

Dart 通过 extends 来继承拓展类,子类可以重写父类方法,通过 supper 来引用父类方法。

class Product {
  void open() {
    //...
  }
   // ...
}

class SmartProduct extends Product {
  void open() {
    super.open();
    //重写加入新的逻辑
  }
  // ...
}
//也可以使用@override注解来表示重写了父类方法 

还有其他注解,如可以使用 @proxy 注解来避免警告信息。

Dart 也支持枚举类型 enum:

enum Color {
  red,
  green,
  blue
}
//使用时候直接调用
Color.blue

可以使用 with 关键字实现多继承:

//看一个官方例子
class Musician extends Performer with Musical {
  // ...
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

Dart 支持静态函数使用,使用时候直接类名.函数名即可。

class Position {

  static num getLongPosition() {
    return 20;
  }
}

void main(){
    //直接调用
    Position.getLongPosition();
}

7 Dart 的泛型和限制域

Java 中泛型使用 T 来表示,Dart 里同样可以使用 T 来表示泛型类型。

abstract class Dog {
  T getDogByName(String name);
  setDogByname(String name, T value);
}

//也可以限制泛型继承自什么类等操作
class Foo {...}

class Extender extends SomeBaseClass {...}

void main() {
  var someBaseClassFoo = new Foo();
  var extenderFoo = new Foo();
  var foo = new Foo();
}

Dart 的库的引入和使用:Dart 使用 import 关键字来导入库和类。

import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';
//如果两个导入的库里的类有重名的,可以使用as关键字
import 'package:utils2/utils2.dart' as utils2;

//也可以只导入库的一小部分
//只导入foo库
import 'package:lib1/lib1.dart' show foo;

//除了foo,其他的都导入
import 'package:lib2/lib2.dart' hide foo;

//延迟载入库,可以减少APP启动时间,优化性能
import 'package:deferred/hello.dart' deferred as hello;
//延迟后,使用的时候使用loadLibrary()来调用
//在一个库上可以多次调用loadLibrary() 函数,只执行载入一次
greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

如果我们想自己创建声明一个库想被别人引用时候,可以用 library 声明:

 // 声明库,名字为abc
  library abc;
  // 导入需要用到的相关库
  import 'dart:html';
  //编写逻辑
  ...
  //如果需要的话,可以借助part关键字来实现部分需求

如果你想声明某个变量、常量、方法函数不能被外部调用,只需要在名字前加上 _ 下划线前缀即可。

8 Dart 的异步处理

Dart 支持异步编程操作,例如我们的网络请求、耗时操作都可以使用。可以使用 async 和 await 关键字来进行标识异步操作。

Dart 里也有 Future 和 Stream 对象进行异步操作,非常的强大和方便。

//例如用await来表示这个方法异步的,需要等待完成后才能继续执行后面的方法
await lookUpVersion()
//要使用 await,其方法必须带有 async 关键字:
checkVersion() async {
  var version = await lookUpVersion();
  if (version == expectedVersion) {
    //执行操作
  } else {
    //执行操作
  }
}
//我们也可以使用Future来修饰包转返回类型,这样我们可以支持数据的后续其他操作
Future lookUpVersion() async => '1.6.0';

在 await 表达式中,表达式的返回值通常是一个 Future 类型;如果返回的值不是 Future,则 Dart 会自动把该值放到 Future 中返回。

Dart 的基础语法知识部分就大概这么多,还有很多细节,大家有兴趣可以进行深入研究使用方法。

总结

本文主要是给大家讲解 Dart 的基础语法部分,为后续 Flutter 的开发学习奠定基础,以期更好地进行深入研究和开发。Dart 的语法比较简单,和 Java 类似,可以对照着理解,全面详细地学习用法后,可以为高效开发做好准备。主要注意点和建议如下:

  • 建议将例子进行编写实践下,使用开发工具输出下结果加深理解;
  • 学习完后,可以进行一个实践练习。

了解更多《Flutter:从入门到实践》

你可能感兴趣的:(Dart 语言基础)