Dart 语言简述

Dart是一种“结构化的web编程”语言,Dart编程语言在所有现代浏览器和环境中提供高性能。Dart是谷歌开发的计算机编程语言,后来被ECMA认定为标准。

Dart重要的概念:

1、所有的东西都是对象。无论是变量、数字、函数等都是对象。所有的对象都是实例。所有的对象都继承自内置的Object类。这点类似于JAVA语言的“一切皆为对象”。

2、程序中指定数据类型使得程序合理地分配内存空间,并帮助编译器进行语法检查。但是,指定类型不是必须的。Dart语言是弱数据类型。

3、Dart代码在运行前解析。指定数据类型和编译时的长列,可以提高运行速度。

4、Dart程序有统一的程序入口:main()。这一点与JAVA、C/C++语言相像。

5、Dart没有public、protected和private的概念。私有特性通过变量或函数加下下划线来表示。

6、Dart的工具可以检查出警告信息(warning)和错误信息(errors)。警告信息只是表明代码可能不工作,但是不会妨碍程序运行。错误信息可以是编译时的错误,也可能是运行时的错误。编译时的错误将阻止程序运行,运行时的错误将会以异常(execption) 的方式呈现。

7、Dart支持anync/await异步处理。

8、关键字

       
abstract 2 dynamic 2 implements 2 show 1
as 2 else import 2 static 2
assert enum in super
async 1 export 2 interface 2 switch
await 3 extends is sync 1
break external 2 library 2 this
case factory 2 mixin 2 throw
catch false new true
class final null try
const finally on 1 typedef 2
continue for operator 2 var
covariant 2 Function 2 part 2 void
default get 2 rethrow while
deferred 2 hide 1 return with
do if set 2 yield 3

避免使用这些单词作为标识符。但是,如有必要,标有上标的关键字可以是标识符:

  • 带有上标1的单词是上下文关键字,仅在特定位置有意义。它们在任何地方都是有效的标识符。

  • 带有上标2的单词是内置标识符。为了简化将JavaScript代码移植到Dart,这些关键字在大多数地方都是有效的标识符,但它们不能用作类或类型名称,也不能用作导入前缀。

  • 带有上标3的单词是与Dart 1.0发布后添加的异步支持相关的有限保留字。不能在任何被标记asyncasync*sync*标记的函数体中使用awaityield作为标识符。

表中的所有其他单词都是保留字,不能是标识符。

Dart语言的常用库

包名 概述
dart:async 异步编程支持,提供Future和Stream类
dart:collection 对dart:core 提供更多的集合支持
dart:convert 不同类型(JSON、UTF-8)间的字符编码、解码支持
dart:core Dart语言内建的类型、对象以及dart语言核心的功能
darr:html 网页开发用到的库
dart:io 文件读写I/O相关操作的库
dart:math 数字常量及函数,提供随机数算法 
dart:svg 事件和动画的矢量图像支持

其中三个开发库的使用频率最高:

dart:core  核心库,包含strings、numbers、collections、errors、dates、URIs等。

dart:html  网页开发里DOM相关的一些库。

dart:io  I/O命令行使用的I/O库。

dart:core库时Dart语言初始已经包含的库,其他的任何库在使用前都需要加上import语句。

变量与基本数据类型:

 在Dart里,变量声明使用var关键字。在Dart语言里一切且为对象,所以如果没有将变量初始化,那么它的默认值为null。

1、常量和固定值

常量及固定值在开发中很常见。如果定义的变量不会变化,可以使用final或const来指明。const是一个编译时的常量;final的值只能被设定一次。

例如:第一行代码设置了一个常量,如果第二行进行重新赋值,那么将引发异常。

final username = "张三";  //定义了一个常量
//username = "李四";  //会引发一个错误

通过对const类型做四则运行将自动得到一个const类型的值。下面代码会得到一个常量,计算圆的面积:

const pi = 3.1415926;
const area = pi * 100 * 100;

可以通过const来创建常量的值,就是说const[]本身是构造函数,示例代码如下:

final stars = const [];
const buttons = const [];

2、基本数据类型

Dart语言常用的基本数据类型包括:Number、String、Boolean、List、Map。

(1)Number类型:包括int整型, double浮点型

int和double类型都是num类型的子类。int类型不能包含小数点。num类型包括的操作有:+,-,*,/以及位移操作>>。num类型包括的常用方法有:abs、ceil和floor。

(2)String类型:字符串类型

可以使用三个单引号或双引号来定义多行的String类型,在Flutter中我们专门用来表示大文本块。

var s1 = '''
var s2 = """
//请注意这是一个用三个引号包裹起来的字符串,可以用来添加多行数据

(3)Boolean类型

Dart是强bool类型检查,只有bool类型的值是true才被认为是true。有的语言里0是false,大于0是true。在Dart语言里则不是,值必须为true或者false。

var sex = "";
if(sex){
  print("你的性别是!" + sex);  
}

上面的示例代码编译不能正常通过,因为sex变量是一个字符串,不是使用条件判断语句,必须用bool类型才可以。

(4)List类型

在Dart语言中,具有一系列相同类型的数据称为List对象。Dart里的List对象类似于JavaScript语言的数组Array对象。

var list = [1, 2, 3];

(5)Map类型

Map类型将key和value关联在一起,也就是键值对。像其他支持Map的编程语言一样,key必须是唯一的。

var week = {
   "Monday" : "星期一",
   "Tuesday" : "星期二",
   "Wednesday" : "星期三",
   "Thursday" : "星期四",
   "Friday" : "星期五",
   "Saturday" : "星期六",
   "Sunday" : "星期日",      
};

//也可以使用Map对象的构造函数Map()来创建Map对象

var week = new Map();
   week[Monday] = "星期一";
   week[Tuesday] = "星期二";
   week[Wednesday] = "星期三";
   week[Thursday] = "星期四";
   week[Friday] = "星期五";
   week[Saturday] = "星期六";
   week[Sunday] = "星期日"; 

添加新的key-value对,再给week添加一个值,注意,其中0为键不是数组的下标索引:week['0'] = '星期一';

检查key是否在Map对象中:assert(week['Monday'] == null);

使用length来获取key-value对的数量,现在我们调用length输出长度为8,原因是刚才后面又添加了一个数据(0),代码如下:print(week.length);

3、函数

Dart是一个面向对象的语言,所以函数也是对象,函数属于Function对象。

函数可以像参数一样传递给其他函数,这样便于做回调处理。

//判断两个字符串是否相等
bool equal(String str1, String str2) {
    retrue str1 == str2;
}

(1)可选参数

将参数使用中括号[]括起来,用来表明是可选位置参数。

例如:总共传入了三个参数,其中name和sex是必须传入的参数,from参数可以不传,代码如下:

//获取用户信息
String getUserInfo(String name, String sex, [String from]) {
  var info = '$name 的性别是 $sex';
  if(from != null){
      info = ‘$info来自$from’;    
  }    
  return info;    
}

void test(){
  pring(getUserInfo(‘小王’, ''));  
}

(2)参数默认值

如果参数指定了默认值,当不传入值时,函数里会使用这个默认值。如果传入了值,则用传入的值取代默认值。通常参数的默认值为null。

改造上面获取用户信息的例子,给from参数赋上默认值,代码如下:

//获取用户信息 使用等号= 来设置默认位置参数
String getUserInfo(String name, String sex, [String from = '中国']) {
  var info = '$name 的性别是 $sex';
  if(from != null){
      info = ‘$info来自$from’;    
  }
  return info;    
}

void test(){
  pring(getUserInfo(‘小王’, ''));  
}

 调用上面的test()方法可以输出“小王的性别是男来自中国”。

(3)main函数

Flutter应用程序必须要有一个main函数,和其他语言一样作为程序的入口函数。 

如下代码表示应用要启动MyApp类:void main() => runApp(MyApp());

(4)函数返回值

在Dart语言中,函数的返回值有如下特点:

  • 所有的函数都有返回值
  • 如果没有指定函数返回值,则默认的返回值是null
  • 没有返回值的函数,系统会在最后添加隐式的return语句

4、运算符

Dart支持各种类型的运算符,并且其中的一些操作符还能进行重载。完整的操作符如下表

描述 运算符
一元后缀 expr++ expr-- () [] . ?.
一元前缀 -expr !expr ~expr ++expr --expr
乘法类型 * / % ~/
加法类型 + -
移动位运算 << >>
位运算 &
异或位运算 ^
位运算 |
关系和类型测试 >= <= > < as is is!
等式 == !=
逻辑与 &&
逻辑或 ||
条件 expr1 ? expr2 : expr3
级联 ..
赋值 = *= /= ~/= %= += -= <<= >>= &= ^= |= ??=

使用运算符时可以创建表达式,以下是运算符表达式的一些示例:
a++
a--
a + b
a = b
a == b
expr ? a : b
a is T

注意使用运算符时的顺序。在运算符表中,操作符的优先级由上到下逐个减小,上面行内的操作符优先级大于下面行内的操作符。例如,“乘法类型”操作符%的优先级比"等阶"操作符==要高,而==操作符的优先级又比"逻辑与"操作符&&要高。

//使用括号来提高可读性
if((n % i == 0) && (d & i == 0));
//难以阅读,但是和上面等阶
if(n % i == 0 && d & i == 0);

提示:对于二元运算符,其左边的操作数将会决定使用的操作符的种类。例如:当你使用一个Vector对象以及一个Point对象时,aVector + aPoint使用的+是由Vector所定义的。

(1)算术运算符

 Dart支持常用的算术运算符:

操作符  含义
+
-
-expr 一元减号,也命名为负号(使后面表达式的值反过来)
*
/
~/ 返回一个整数值的除法
% 取余,除法剩下的余数
++var var=var+1 表达式的值为var+1
var++ var=var+1 表达式的值为var
--var var=var-1 表达式的值为var-1
var-- var=var-1 表达式的值为var

示例代码如下:

assert(3 + 6 == 9);
assert(3 - 6 == -3);
assert(3 * 6 == 18);
assert(7 / 2 == 3.5); //结果是浮点型
assert(5 ~/2 == 2); //结果是整形
assert(5 % 2 == 1); //求余数

var a, b;
a = 0;
b = ++a; //在b获得其值之前自增a
assert(a == b); //1 == 1

a = 0;
b = a++; //在b获得值后自增a
assert(a != b); //1 != 0

a = 0;
b = --a; //在b获得其值之前自减a
assert(a == b); //-1 == -1

a = 0;
b = a--; //在b获得值后自减a
assert(a != b); //-1 != 0

(2)关系运算符

操作符 含义
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

有时候需要判断两个对象是否相等,请使用==运算符。

(3)类型测试操作符

as、is和is! 操作符在运行时用于检查类型非常方便,含义如下:

操作符 含义
as 类型转换
is 当对象时相应类型时返回true
is! 当对象不是相应类型时返回true

如果obj实现了T所定义的接口,那么obj is T 将返回true。

使用as操作符可以把一个对象转换为制定类型,前提是能够转换。转换之前用is判断一下更保险。如下代码:

if(user is User){
  //类型检测
  user.name = 'Flutter';  
}

//如果能确定user时User的实例,则可以通过as直接简化代码:
(user as User).name = ‘Flutter’;

注意:上面两段代码并不相等,如果user的值为null或者不是一个User对象,则第一段代码不会做出任何事情,第二段代码会报错。

(4)赋值操作符

可以使用 = 运算符赋值。要仅在变量为null时赋值,请使用 ??= 运算符。如下代码所示:

//赋值给a
a = value;
//如果b为空,则将值分配给b;否则b保持不变
b ??= value;

诸如+=之类的复合赋值运算符将操作符与赋值相结合。以下是复合赋值运算符的工作方式:

复合赋值符 等式表达式
a op b a = a op b
a += b a = a + b
a -= b a = a - b

(5)逻辑运算符

可以使用逻辑运算符反转或组合布尔表达式。逻辑运算符如下所示:

操作符 含义
!expr 反转以下表达式(将false更改为true,反之亦然)
|| 逻辑或
&& 逻辑与

示例代码如下:

if(!expr && (test == 1 || test == 8)) {
  ......  
}

(6)位运算符

通常我们指位运算为<< 或 >> 移动位运算,通过操作位的移动来达到运算的目的,而&、|、^、~expr也是操作位来达到运算的目的。

操作符 含义
&
|
^ 异或
~expr 一元位补码(0s变为1s;1s变为0s)
<< 左移
>> 右移

示例代码如下:

final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); //
assert((value & -bitmask) == 0x20); //与非
assert((value | bitmask) == 0x2f); //
assert((value ^ bitmask) == 0x2d); //异或
assert((value << 4) == 0x220); //左移
assert((value >> 4) == 0x02); //右移

(7)条件表达式

Dart由两个运算符,可用来简明地评估可能需要if-else语句的表达式。如下代码即为一种条件表达式,也可以称为三元表达式,如果条件为真,返回expr1,否则返回expr2.

condition ? expr1 : expr2;

第二种如下表示,如果expr1为非空,则返回其值;否则,计算并返回expr2的值。

expr1 ?? expr2;

(8) 级联操作

级联操作用两个点(..)表示,可对同一对象执行一系列操作。类似于Java语言里点点点处理或JavaScript里的Promise的then处理。级联操作主要的目的是为了简化代码。

querySelector('#btnOK') { //获取一个id为btnOK的按钮对象
    ..text = '确定'  //使用它的成员
    ..classes.add('ButtonOKStyle');
    ..onClick.listen((e) => window.alert('确定'));      
}

//相当于

var button = querySelector('#btnOK');
button.text = '确定';
button.classes.add(' ' ButtonOKStyle ' ');
button.onClick.listen((e) => window.alert('确定')); 

第一个方法调用querySelector,返回一个按钮对象,然后再设置它的文本为“确定”,再给这个按钮添加一个样式叫“ButtonOKStyle”,最后在监听单击事件,事件弹出一个显示“确定”的Alert。

注意:严格来说,级联的“双点”符号不是运算符。这只是Dart语法的一部分。

5、流程控制语句

Dart语言的流程控制语句如下:if和else、for(循环)、while和do-while(循环)、break和continue、switch和case、assert(断言)、try-catch和throw。

(1)if和else

Dart支持if及else的多种组合。

String today = 'Monday';
if(today == 'Monday') {
  print('今天是星期一');  
}else if(today == 'Tuesday') {
  print('今天是星期二');
}else {
  print('今天是个好日子');  
}
//输出'今天是星期一',条件语句走到第一条判断就停止了。

(2)for(循环)

下面举例说明for循环,首先定义了一个字符串“Hello Dart”,然后使用for循环向message变量里写入5个同样的字符“!”。

var message = new StringBuffer('Hello Dart');
for(var i = 0; i < 5; i ++) {
    message.write(i);
}
print(message);
//输出“Hello Dart!!!!!”,注意值是字符串向尾部添加的。

//除了常规的for循环外,针对可以序列化的操作数,可以使用forEach()方法,当不关心操作数的当前下标时,forEach()方法师很简便的。
var arr = [0, 1, 2, 3, 4, 5, 6];
for(var v in arr){
  print(v);
}
//按序列输出 0 1 2 3 4 5 6

(3)while和do-while(循环)

下面举例说明while循环,其中定义了一个变量temp,temp在循环体内自动加1,当条件(temp<5)不满足时会推出循环,代码如下:

var _temp = 0;
while(_temp < 5) {
  print('这是一个循环:' + (_temp).toString());
  _temp ++;
}


var _temp = 0;
do{
  print(‘这是一个循环:’ + (_temp).toString());
  _temp ++;  
}while(_temp < 5);

//都输出
//flutter:这是一个循环:0
//flutter:这是一个循环:1
//flutter:这是一个循环:2
//flutter:这是一个循环:3
//flutter:这是一个循环:4

(4)break和continue

break用来跳出循环,改造前面的循环例子:

var arr = [0, 1, 2, 3, 4, 5, 6];
for(var v in arr){
  if(v == 2){
     break;
  }  
  print(v);
}
//当v等于2的时候跳出循环,所以输出“0,1”。现在把break改为continue

var arr = [0, 1, 2, 3, 4, 5, 6];
for(var v in arr){
  if(v == 2){
     //break;
     continue;
  }  
  print(v);
}
//改为continue后,当v等于2的时候只是跳出本次循环,代码还会继续往下执行,所以输出结果是“0,1,3,4,5,6”

(5)switch和case

Dart中switch/case语句使用==操作来比较整数、字符串或其他编译过程中的常量,从而实现分支的作用。switch/case语句的前后操作数必须是相同类型的对象实例。每一个非空的case子句最后都必须跟上break语句。

String today = 'Monday';
switch(today) {
  case 'Monday' : 
    print('星期一');
    break;
  case 'Tuesday' :
    print('星期二');
    break;
}

(6)assert(断言)

Dart语言通过使用assert语句来中断正常的执行流程,当assert判断的条件为false时发生中断。assert判断的条件是任何可以转化为boolean类型的对象,即使是函数也可以。如果assert的判断为true,则继续执行下面的语句;反之则会抛出一个断言错误异常AssertionError。

//确定变量的值不为null
assert(text != null);

6、异常处理

异常是表示发生了意外的错误,如果没有捕获异常,引发异常的隔离程序将被挂起。并且程序将终止。

Dart代码可以抛出并捕获异常,但与Java相反,Dart的所有异常都是未检查的异常。方法不声明它们可能抛出那些异常,也不需要捕获任何异常。

Dart提供了异常和错误类型以及许多预定义的子类型。当然,也可以定义自己的异常。然后,Dart程序可以抛出任何非空对象。

(1)抛出异常

下面是一个抛出或引发异常的例子:

throw FormatException('抛出一个FormatException异常');

你也可以抛出任意对象: 

throw '数据非法!';

提示:稳定健壮的程序一定是做了大量异常处理的,所以建议你在编写程序时尽量考虑到可能发生异常的情况。

(2)捕获异常

你可以指定一个或两个参数来捕获异常(catch),第一个是抛出的异常,第二个是堆栈跟踪(StackTrace 对象)。如下代码所示:

try {
         //...
      }on Exception catch (e) {
         print('Exception details:\n $e');
      }catch (e, s) {
         pring('Exception details:\n $e');
         pring('Stack trace:\n $s');
      } 
//上面的代码第一个catch用来捕获异常详细信息,第二个catch是堆栈跟踪信息

(3)Finally

要确保某些代码能够运行,无论是否抛出异常,请使用finally子句。如果没有catch子句匹配异常,则异常在finally子句运行后传播。如下面代码所示,在最下面加上了finally语句:

try {
         //...
      }on Exception catch (e) {
         print('Exception details:\n $e');
      }catch (e, s) {
         pring('Exception details:\n $e');
         pring('Stack trace:\n $s');
      }finally {
         print('Do some thing:\n');
      }

7、面向对象

Dart作为高级语言支持面向对象的很多特性,并且支持基于mixin的继承方式。基于mixin的继承方式是指:一个类可以继承自多个父类,相当于其他语言里的多继承。所有的类都有同一个基类Object,这个特性类似于Java语言,Java所有的类也都是继承自Object,也就是说一切皆为对象。

使用new语句实例化一个类,如下所示:

//实例化了一个User类的对象user
var user = new User('张三', 20);

(1)实例化成员变量

定义一个User类,在里面添加两个成员变量name和age,代码如下:

class User{
  String name; //name成员变量
  String age; //age成员变量
}    

类定义中所有的变量都会隐式的定义setter方法,针对非空的变量会额外增加getter方法。实例化成员变量请参考如下代码:

class User{
  String name; //name成员变量
  Int age; //age成员变量
}
main() {
  var user = new User();
  user.name = '张三'; //相当于使用了name的setter方法
  user.age = 20;
}

(2)构造函数

①常规构造函数

构造函数是用来构造当前类的函数,是一个特殊的函数,函数名称必须要和类名相同才行。如下代码为User类添加了一个构造函数,函数里给User类的两个成员变量初始化了值:

class User{
  String name;
  int age;
  User(String name, int age) {
    this.name = name;
    this.age =age;
  }
}

//this关键词指向了当前类的实例,上面的代码可以简化为:

class User{
  String name;
  int age;
  User(this.name, this.age);
}

②命名的构造函数

使用命名构造函数从另一类或现有的数据中快速实现构造函数,代码如下:

class User {
  String name;
  int age;
 
  User(this.name, this.age);
  
  //命令构造函数
  User.fromJson(Map json) {
     name = json['nage'];
     age = json['age'];
  }
}

③构造函数初始化列表

除了调用父类的构造函数,也可以通过初始化列表在子类的构造函数运行前来初始化实例的成员变量值。代码如下:

class User {
  final String name;
  final int age;
  
  User(name, age)
         : name = name,
           age = age;
}

main() {
  var p = new User('张三', 20);
}

(3)读取和写入对象

 get()和set()方法是专门用于读取和写入对象的属性方法,每一个类的实例,系统都隐式地包含有get()和set()方法。这和很多语言里的VO类相似。

例如,定义一个矩形的类,有上、下、左、右四个成员变量:top、bottom、left、right,使用get及set关键字分别对right及bottom进行获取和设置值。代码如下:

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

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

  //获取right值
  num get right  => left + width;

  //设置right值 同时left也发生变化
  set right(num value)  => left = value - width;
  
  //获取bottom值
  num get bottom => top + height;

  //设置bottom值 同时top也发生变化
  set bottom(num value)  => value - height;
}

main(){
  var rect = new Rectangle(3, 4, 20, 15);

  print('left:' + rect.left.toString());
  print('right:' + rect.right.toString());
  rect.right = 30;
  print('更改right值为30');
  print(‘left:’ + rect.left.toString());
  print('right:' + rect.right.toString());

  print('top:' + rect.top.toString());
  print('bottom:' + rect.bottom.toString());
  rect.bottom= 50;
  print('更改bottom值为50');
  print('top:' + rect.top.toString());
  print('bottom:' + rect.bottom.toString());
}
//对应的输出为:
//flutter: left:3
//flutter: right:23
//flutter: 更改right值为30
//flutter: left:10  //30-20
//flutter: right:30
//flutter: top:4
//flutter: bottom:19
//flutter: 更改bottom值为50
//flutter: top:35  //50-15
//flutter: bottom:50

(4)重载操作

编写一个例子,定义一个Vector向量类,编写两个方法分别用于重载加号以及减号,那么两个向量相加,就表示它们的x值及y值相加,当两个向量相减,就表示它们的x值及y值相减。

//定义一个向量类
class Vector {
  final int x;
  final int y;
  const Vector(this.x, this.y);

  //重载加号 + (a + b)
  Vector operator +(Vector v) {
     retrun new Vector(x + v.x, y + v.y);
  }

  //重载减号 - (a - b)
  Vector operator -(Vector v) {
     retrun new Vector(x - v.x, y - v.y);
  }
}

main() {
  //实例化两个向量
  final v = new Vector(2, 3);
  final w = new Vector(2, 2);
  final r1 = v + w;
  print('r1.x=' + r1.x.toString() + ' r1.y=' + r1.y.toString());
  final r2 = v - w;
  print('r2.x=' + r2.x.toString() + ' r2.y=' + r2.y.toString());
}

//上面输出结果为:
//flutter: r1.x=4  r1.y=5   //2+2  2+3
//flutter: r2.x=0  r1.y=1   //2-2  3-2

(5)继承类

继承是面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法;或子类从父类继承方法,使得子类具有父类相同的行为。Dart里使用extends关键字来创建一个子类,super关键字来制定父类。

 例子:定义一个动物类,动物具有吃和跑两种能力。再定义一个人类,人类是属于动物类的,人类不仅会吃和会跑,还会说、会学习。所以人类相当于动物类的一个扩展。具体代码:

//动物类
class Animal {
  //动物会吃
  void eat() {
    print('动物会吃');  
  }
  //动物会跑
  void run() {
    print('动物会跑');  
  }
}  

//人类
class Person extends Animal{
  //人类会说
  void say() {
    print('人类会说');
  }
  //人类会学习
  void study() {
    print('人类会学习');
  }
}  

main() {
  print('实例化一个动物类');
  var animal = new Animal();
  animal.eat();
  animal.run();

  print('实例化一个人类');
  var person = new Person();
  person.eat();
  person.run();
  person.say();
  person.study();
}
//输出结果:
//flutter:实例化一个动物类
//flutter:动物会吃
//flutter:动物会跑
//flutter:实例化一个人类
//flutter:动物会吃
//flutter:动物会跑
//flutter:人类会说
//flutter:人类会学习

(6)抽象类

抽象类类似于Java语言中的接口。抽象类里不具体实现方法,只是写好定义接口,具体实现留着调用的人去实现。抽象类可以使用abstract关键字定义类。

例子:定义一个抽象类叫DateBaseOperate,里面定义4个数据库常用的操作方法“增删改查”。再定义一个类命名为DateBaseOperateImpl继承自DateBaseOperate用来实现抽象类里的方法。代码如下:

//数据库操作抽象类
abstract class DateBaseOperate {
  void insert();  //定义插入的方法
  void delect();  //定义删除的方法
  void update();  //定义更新的方法
  void query();    //定义查询的方法
}

//数据库操作实现类
class DateBaseOperateImpl extends DateBaseOperate {
  //实现了插入的方法
  void insert() {
    print('实现了插入的方法');
  }
  //实现了删除的方法
  void delect() {
    print('实现了删除的方法');
  }
  //实现了更新的方法
  void update() {
    print('实现了更新的方法');
  }
  //实现了查询的方法
  void query() {
    print('实现了查询的方法');
  }  
}    

main(){
  var db = new  DateBaseOperateImpl();
  db.insert();
  db.select();
  db.update();
  db.query();
}
//输出结果为:
//flutter:实现了插入的方法
//flutter:实现了删除的方法
//flutter:实现了更新的方法
//flutter:实现了查询的方法

(7)枚举类型

枚举类型是一种特殊的类,通常用来表示相同类型的一组常量值。每个枚举类型都用于一个index的getter,用来标记元素的元素位置。第一个枚举元素的索引是0.

enum Color {
  red,
  green,
  blue
}

获取枚举类中所有的值,使用value常用:

List colors = Color.values;

因为枚举类型里面的每个元素都是相同类型,可以使用switch语句来针对不同的值做不同的处理,示例代码如下:

enum Color {
  red,
  green,
  blue
}
//定义一个颜色变量 默认值为蓝色
Color aColor = Color.blue;
switch (aColor) {
  case Color.red:
    print('红色');
    break;
  case Color.green:
    print('绿色');
    break;
  default: //默认颜色
    pring(aColor); //Color.blue
}

(8)Mixins

Mixins(混入功能)相当于多继承,也就是说可以继承多个类。使用with关键字来实现Mixins的功能。示例代码如下:

class S {
  a() {print('S.a');}
}
class A {
  a() {print('A.a');}
  b() {print('A.b');}
}

class T = A with S;

main(List args) {
  T t = new T();
  t.a();
  t.b();
}
//上面代码从结果来看T具有了S及A两个类的方法
//S.a
//A.b

8、泛型

泛型通常是为了类型安全而设计的,适当地指定泛型类型会生成更好的代码,可以使用泛型来减少代码重复。Dart中使用的方式来定义泛型。

例如,如果想要List只包含字符串,可以将其声明为list。如下所示:

var names = new List();
names.addAll(['张三', '李四', '王五']);

(1)用于集合类型

泛型用于List和Map类型参数化:List:      Map:

例子:

var names = ['张三', '李四', '王五'];
var weeks = {
  'Monday' : '星期一',
  ‘Tuesday' : '星期二',
  'Wednesday' : '星期三',
  'Thursday' : '星期四',
  'Friday' : '星期五',
  'Saturday' : '星期六',
  'Sunday' : '星期日',
};

(2)在构造函数中参数化

Map类型的例子如下:

var users = new Map();

9、库的使用

(1)引用库

通过import语句在一个库中引用另一个库的文件。需要注意以下事项:

  • 在import语句后面需要接上库文件的路径。
  • 对Dart语言提供的库文件使用dart:xx格式。
  • 第三方的库文件使用package:xx格式。

import例子:

import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';

(2)指定一个库的前缀

当引用的库拥有相互冲突的名字,可以为其中一个或几个指定不一样的前缀。这与命名空间的概念比较接近。示例代码如下:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
//...
Element element1 = new Element();  //使用lib1中的Element
lib2.Element element2 = new lib2.Element();  //使用lib2中的Element

lib1/lib1.dart及lib2/lib2.dart里都有Element类,如果直接引用就不知道具体引用那个Element类,所以代码中把lib2/lib2.dart指定成lib2,这样使用lib.Element就不会发生冲突。

(3)引用库的一部分

如果只需要使用库的一部分内容,可以有选择的引用,有如下关键字:

  • show关键字:只引用一点。
  • hide关键字:除此之外都引用。

示例代码如下:

//导入foo
import 'package:lib1/lib1.dart' show foo;

//除了foo导入其他所有内容
import 'package:lib1/lib1.dart' hide foo;

10、异步支持

Dart语言是目前少数几个支持异步操作的语言。一般使用async函数和await表达式实现异步操作。

Dart库提供asynchronous功能,该功能提供接口来进行耗费时间的操作,比如文件读写、网络请求。该功能返回Future或Stream对象。

可以通过如下的方式来获取asynchronous功能返回的Future对象的值:

  • 使用async函数和await表达式。
  • 使用Future功能提供的API。

可以通过如下的方式来获取asynchronous功能返回的Stream对象的值:

  • 使用async和一个异步的循环(await for)。
  • 使用Stream的相关API。

下面的例子代码使用了async或await异步处理,虽然代码看起来像是同步处理的:await readFile()

必须在一个使用了async关键字标记后的函数中使用await表达式:

fileOperate () async {
  //读取文件
  var file = await readFile();
  //其他处理
}

11、元数据 

使用元数据给代码添加更多的信息。元数据是以@开始的修饰符,在@后面接着编译时的常量或调用一个常量构造函数。目前Dart语言提供三个@修饰符:

(1)@deprecated被弃用的

(2)@override重写

(3)@proxy代理

使用@voerride修饰符可以重写父类方法。改造之前写的例子,人类重写eat方法,代码如下:

//动物类
class Animal {
  //动物会吃
  void eat(){
    print('动物会吃');
  }
  //动物会跑
  void run(){
    print('动物会跑');
  }
}

//人类
class Person extends Animal {
  //人类会说
  void say(){
    print('人类会说');
  }  
  //人类会学习
  void study(){
    print('人类会学习);
  }

  @override
  //人类也会吃
  void eat(){
    print('人类也会吃');
  }
}

main() {
  print('实例化一个动物类');
  var animal = new Animal();
  animal.eat();
  animal.run();
  print('实例化一个人类');
  var person = new Person();
  person.eat();
  person.run();
  person.say();
  person.study();
}
//输出结果是
//flutter:实例化一个动物类
//flutter:动物会吃
//flutter:动物会跑
//flutter:实例化一个人类
//flutter:人类也会吃
//flutter:动物会跑
//flutter:人类会说
//flutter:人类会学习

元数据可以修饰library(库)、class(类)、typedef(类型定义)、type parameter(类型参数)、constructor(构造函数)、factory(工厂函数)、function(函数)、field(作用域)、parameter(参数)、variable declaration(变量声明)。

12、注释

 Dart支持三种注释类型:单行注释、多行注释、文档注释。

(1)单行注释:以//开头。从//开始到一行结束的所有内容都会被Dart编译器忽略。

(2)多行注释:以/*开头,以*/结束,之间的所有内容都会被Dart编译器忽略。

(3)文档注释:以/**或///开头。

转载于:https://www.cnblogs.com/joe235/p/11152040.html

你可能感兴趣的:(Dart 语言简述)