Dart语言基础


学习一门编程语言,首页要了解它的历史和特点。Dart是Google公司推出的编程语言,于2011年就已经亮相了。Dart也是一门面向对象的语言,语法和Java,C,JavaScript很像。所以会Java语言,学习Dart一般会快一些。Dart里所有的类都可以看成是对象,是单继承,动态类语言。可以进行移动应用、Web应用、服务器应用、PC应用、物联网应用的开发等等,还在不断的拓展开发平台。我们的主角Flutter就是基于Dart语言编写的,未来的Flutter将会是移动应用、Web应用、PC应用等平台的跨平台高性能框架。接下来的课程里,我们就开始进行Dart语言的基础语法学习。本文将主要介绍:

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

Dart简单介绍

为什么要介绍Dart?因为Flutter是基于Dart编程语言编写的一个跨平台框架。所以一些语法是基于Dart语法来使用的,Google计划未来的Flutter将会是移动应用、Web应用、PC应用等平台的跨平台高性能框架,也是未来的Fuchsia操作系统的主要框架。那么接下来就简单介绍下Dart语言。

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

接下来看下Dart的特性:

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

Dart的语法特点:

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

Dart的关键字

好了,说了这么多,接下来改进入正题了,进入学习一门语言需要掌握的一些基本知识。首先看下Dart的关键字:(33个保留字,17个内置标志符)

33个Dart保留字:

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

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*

Dart的数据类型

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

1// 这是程序执行的入口 2main() { 3 var number = 30; // 定义变量number并进行赋值初始化 4 printNumber(number); // 调用方法 5} 6 7// 定义方法printNumber 8printNumber(num aNumber) { 9 print('The number is $aNumber.'); // 在控制台打印输出内容 10} 11 12 13

这个例子涵盖了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位双精度浮点型数据类型。举个例子:

1void main() { 2 //定义int和double类型 3 int a = 6; 4 double b = 3.18; 5 print('$a ,$b'); 6 7 // String转int 8 int twoInt = int.parse('2'); 9 // String转double 10 var twoDouble = double.parse('2.2'); 11 print('$twoInt ,$twoDouble'); 12 13 // int转String 14 String intToString = 2.toString(); 15 // double转String,后面需加入保留小数点位数 16 String doubleToString = 3.23456.toStringAsFixed(2); 17 print('$intToString,$doubleToString'); 18 19 //自动四舍五入 20 String fiveString = 2.12832.toStringAsFixed(2); 21 print(fiveString); 22} 23 24

输出结果为:

16 ,3.18 22 ,2.2 32,3.23 42.13 5 6

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

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

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

再来看一个例子:

1void main() { 2 //单引号和双引号定义 3 String singleString = 'A singleString'; 4 String doubleString = "A doubleString"; 5 print('$singleString ,$doubleString'); 6 7//使用$字符引用变量,使用{}引入表达式 8 String userS = 'It\'s $singleString'; 9 String userExpression = 'It\'s expression,${singleString.toUpperCase()}'; 10 print('$userS'); 11 print('$userExpression'); 12 13//使用引号字符串邻接来拼接或者使用+号连接字符串 14 String stringLines = 15 'String ' 'concatenation' " works even over line breaks."; 16 String addString = 'A and ' + 'B'; 17 print('$stringLines'); 18 print('$addString'); 19 20//使用三个引号(单引号或双引号)来创建多行字符串 21 String s3 = ''' 22You can create 23multi-line strings like this one. 24'''; 25 String s33 = """This is also a 26multi-line string."""; 27 print('$s3'); 28 print('$s33'); 29 30//使用r为开头,显示定义一个原始字符串 31 String s = r"It is a \n raw string."; 32 print('$s'); 33} 34 35

输出结果为:

1A singleString ,A doubleString 2It's A singleString 3It's expression,A SINGLESTRING 4String concatenation works even over line breaks. 5A and B 6You can create 7multi-line strings like this one. 8 9This is also a 10multi-line string. 11It is a \n raw string. 12 13

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

1var name = 'Tom'; 2if (name) { 3 // JavaScript可以这样写,Dart不行 4 print('He is Tom!'); 5} 6 7// JavaScript可以这样写,Dart不行 8if (1) { 9 print('A line Data.'); 10} else { 11 print('A good Data.'); 12} 13 14

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

1void main() { 2 //定义初始化一个集合 3 var list = [1, 2, 3]; 4 List listData = [5, 6, 7]; 5 print(list.length); 6 print(list[0]); 7 //集合数据赋值 8 listData[1] = 8; 9 print(listData[1]); 10 //如果在集合前加了const关键字,集合数据不可以进行操作 11 var constantList = const [1, 2, 3]; 12 List datas = List(); 13 datas.add('data1'); 14 datas.addAll(['data2', 'data3', 'data4', 'data5', 'data6']); 15 //输出第一个元素 16 print(datas.first); 17 // 获取最后一个元素 18 print(datas.last); 19 // 获取元素的位置 20 print(datas.indexOf('data1')); 21 // 删除指定位置元素 22 print(datas.removeAt(2)); 23 //删除元素 24 datas.remove('data1'); 25 //删除最后一个元素 26 datas.removeLast(); 27 // 删除指定范围元素,含头不含尾 28 datas.removeRange(0, 2); 29 //删除指定条件的元素 30 datas.removeWhere((item) => item.length > 3); 31 // 删除所有的元素 32 datas.clear(); 33 //其他方法可以自己尝试 34} 35 36

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

1void main() { 2 //定义一个map并赋值 3 var gifts = { 4 // Keys Values 5 'first': 'dog', 6 'second': 'cat', 7 'fifth': 'orange' 8 }; 9 10 var nobleGases = { 11 // Keys Values 12 2: 'a', 13 10: 'b', 14 18: 'b', 15 }; 16 //定义一个map并赋值 17 Map map = Map(); 18 map['first'] = 'a-value'; 19 map['second'] = 'b-value'; 20 map['fifth'] = 'c-value'; 21 Map nobleGasesMap = Map(); 22 nobleGasesMap[2] = 'a-value'; 23 nobleGasesMap[10] = 'b-value'; 24 nobleGasesMap[18] = 'c-value'; 25 //指定键值对类型 26 var nobleGases = new Map<int, String>(); 27 //获取某个key的value 28 print(map['first']); 29 //获取map大小 30 print(map.length); 31 //定义一个不可变的map 32 final constantMap = const { 33 2: 'a', 34 10: 'b', 35 18: 'c', 36 }; 37 //其他API用法和List类似 38} 39 40

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

1void main() { 2 //看一个官方例子 3 var clapping = '\u{1f44f}'; 4 print(clapping); 5 print(clapping.codeUnits); 6 print(clapping.runes.toList()); 7 8 Runes input = new Runes( 9 '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); 10 print(new String.fromCharCodes(input)); 11} 12 13

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

1 //看一个官方例子 2 #radix 3 #bar 4 5

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) =   *=   /=   ~/=   %=   +=   -=   <<=   >>=   &=   ^=  

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

Dart的流程控制语句

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

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

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

1void main() { 2 //if和else 3 if (hasData()) { 4 print("hasData"); 5 } else if (hasString()) { 6 print("hasString"); 7 } else { 8 print("noStringData"); 9 } 10 11 //for循环 12 var message = new StringBuffer("Dart is good"); 13 for (var i = 0; i < 6; i++) { 14 message.write(','); 15 } 16 17 //while 18 while (okString()) { 19 print('ok'); 20 } 21//do-while 22 do { 23 print('okDo'); 24 } while (!hasData()); 25 26 //break和continue 27 while (true) { 28 if (noData()) { 29 break; 30 } 31 if (hasData()) { 32 continue; 33 } 34 doSomething(); 35 } 36 37 //switch和case 38 var command = 'OPEN'; 39 switch (command) { 40 case 'A': 41 executeA(); 42 break; 43 case 'B': 44 executeB(); 45 break; 46 case 'C': 47 executeC(); 48 break; 49 default: 50 executeUnknown(); 51 } 52 53 //Assert(断言) 54 assert(string != null); 55 assert(number < 80); 56 assert(urlString.startsWith('https')); 57} 58 59

Exceptions异常捕获处理:

使用throw抛出异常:

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

也可以抛出其他类型对象

1throw 'no data!'; 2 3

使用catch捕获异常:

1try { 2 getData(); 3} on OutOfLlamasException { 4 sendData(); 5} on Exception catch (e) { 6 print('Unknown data Exception: $e'); 7} catch (e) { 8 print('Some Exception really unknown: $e'); 9} 10 11

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

1//给出一个官方例子 2final foo = ''; 3 4void misbehave() { 5 try { 6 foo = "You can't change a final variable's value."; 7 } catch (e) { 8 print('misbehave() partially handled ${e.runtimeType}.'); 9 rethrow; // rethrow重新抛出,允许main()里的函数继续捕获处理异常 10 } 11} 12 13void main() { 14 try { 15 misbehave(); 16 } catch (e) { 17 print('main() finished handling ${e.runtimeType}.'); 18 } 19} 20 21

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

1try { 2 getData(); 3} catch(e) { 4 print('Error: $e'); 5} finally { 6 //始终执行 7 sendData(); 8} 9 10

Dart的类和函数(方法)

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

1var map=Map(); 2var map2=new Map(); 3 4

调用类方法:

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

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

1 a?.name = 'Tom'; 2 3

关于获取对象的类型,可以使用Object的runtimeType属性来获取实例的类型。
先看一个实例化对象,并获取和调用属性和方法的例子,和Java用法基本一致:

1class Position { 2 num x; 3 num y; 4 methodPosition(){ 5 ... 6 } 7} 8 9void main() { 10 var pos = new Position(); 11 pos.x = 5;//赋值 12 print(pos.x);//取值 13 pos.methodPosition();//调用方法 14} 15 16

定义同名构造方法:

1class Position { 2 num x; 3 num y; 4 5 Position(num x, num y) { 6 this.x = x; 7 this.y = y; 8 } 9} 10//也可以这样简化定义构造方法 11class Point { 12 num x; 13 num y; 14 15 Point(this.x, this.y); 16} 17 18 19

注意Dart的构造函数不可以继承,父类的构造函数也不可以继承。
Dart也支持抽象函数(抽象类):

1abstract class Dog { 2 //可以定义变量和抽象方法 3 4 void doSomething(); // 定义抽象方法 5} 6 7class GoodDog extends Dog { 8 void doSomething() { 9 //实现逻辑 10 } 11} 12 13

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

1 2class Comparable { 3 final _name; 4 5 Comparable(this._name); 6 7 String good1(who) => 'Hello'; 8} 9 10class Location { 11 Location(); 12 13 String good2() => 'World!'; 14} 15 16class ImlClass implements Comparable, Location { 17 // ... 18} 19 20

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

1class Product { 2 void open() { 3 //... 4 } 5 // ... 6} 7 8class SmartProduct extends Product { 9 void open() { 10 super.open(); 11 //重写加入新的逻辑 12 } 13 // ... 14} 15//也可以使用@override注解来表示重写了父类方法 16 17

还有其他注解,如可以使用 @proxy 注解来避免警告信息:
Dart也支持枚举类型enum:

1enum Color { 2 red, 3 green, 4 blue 5} 6//使用时候直接调用 7Color.blue 8 9

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

1//看一个官方例子 2class Musician extends Performer with Musical { 3 // ... 4} 5 6class Maestro extends Person 7 with Musical, Aggressive, Demented { 8 Maestro(String maestroName) { 9 name = maestroName; 10 canConduct = true; 11 } 12} 13 14

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

1class Position { 2 3 static num getLongPosition() { 4 return 20; 5 } 6} 7 8void main(){ 9 //直接调用 10 Position.getLongPosition(); 11} 12 13

Dart的泛型和限制域

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

1abstract class Dog<T> { 2 T getDogByName(String name); 3 setDogByname(String name, T value); 4} 5 6//也可以限制泛型继承自什么类等操作 7class Foo<T extends SomeBaseClass> {...} 8 9class Extender extends SomeBaseClass {...} 10 11void main() { 12 var someBaseClassFoo = new Foo<SomeBaseClass>(); 13 var extenderFoo = new Foo<Extender>(); 14 var foo = new Foo(); 15} 16 17

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

1import 'dart:io'; 2import 'package:mylib/mylib.dart'; 3import 'package:utils/utils.dart'; 4//如果两个导入的库里的类有重名的,可以使用as关键字 5import 'package:utils2/utils2.dart' as utils2; 6 7//也可以只导入库的一小部分 8//只导入foo库 9import 'package:lib1/lib1.dart' show foo; 10 11//除了foo,其他的都导入 12import 'package:lib2/lib2.dart' hide foo; 13 14//延迟载入库,可以减少APP启动时间,优化性能 15import 'package:deferred/hello.dart' deferred as hello; 16//延迟后,使用的时候使用loadLibrary()来调用 17//在一个库上可以多次调用loadLibrary() 函数,只执行载入一次 18greet() async { 19 await hello.loadLibrary(); 20 hello.printGreeting(); 21} 22 23

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

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

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

Dart的异步处理

Dart支持异步编程操作,例如我们的网络请求、耗时操作都可以使用。可以使用async和await关键字来进行标识异步操作。
Dart里也有Future和Stream对象进行异步操作,非常的强大和方便。

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

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

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

代码交流 2021