Dart 语言简述

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

Dart重要的概念:mysql

一、全部的东西都是对象。不管是变量、数字、函数等都是对象。全部的对象都是实例。全部的对象都继承自内置的Object类。这点相似于JAVA语言的“一切皆为对象”。程序员

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

三、Dart代码在运行前解析。指定数据类型和编译时的长列,能够提升运行速度。算法

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

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

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

七、Dart支持anync/await异步处理。编程

八、关键字json

       
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。

全局变量特色:全局变量常驻内存、全局变量污染全局
局部变量特色:不常驻内存会被垃圾机制回收、不会污染全局

一、常量和固定值

常量及固定值在开发中很常见。若是定义的变量不会变化,可使用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 [];

二、基本数据类型

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

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

int和double类型都是num类型的子类。int类型不能包含小数点。

int必须是整型;double便可以是整型,也能够是浮点型。

num类型包括的操做有:+,-,*,/,% 以及位移操做>>。num类型包括的经常使用方法有:abs、ceil和floor。

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

String str = "This is flutter";

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

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

字符串类型拼接:

String str1 = "Hello"; String str2 = "World" print(str1 + str2); //Hello World
print(str1 + " " + str2); //Hello World

(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对象。

//第一种定义List方式
var list1 = [1, 2, 3]; //第二种定义List方式
var list2 = new List(); list2.add("a"); list2.add(123); list2.add("c"); //定义List指定类型
var list3 = new List<String>(); list3.add("a"); list3.add("b");

List经常使用属性

length    长度
reversed    翻转
isEmpty    是否为空
isNotEmpty    是否不为空


var arr = ["香蕉","苹果","橘子"]; print(arr.length); //3
print(arr.reversed); //(橘子, 苹果, 香蕉)
print(arr.isEmpty); //false
print(arr.isNotEmpty); //true

var newArr = arr.reversed.toList(); print(newArr); //[橘子, 苹果, 香蕉]

List经常使用方法

add    增长
addAll    拼接数据
indexOf    查找 传入具体值
remove    删除 传入具体值
removeAt    删除 传入索引值
fillRange    修改
insert(index,value);    指定位置插入
insertAll(index,list);    指定位置插入List
toList()     其余类型转换成List
join()     List转换成字符串
split() 字符串转换成List
forEach()
map
where
any
every














var arr = ["香蕉","苹果","橘子"]; arr.add("桃子"); print(arr); //[香蕉, 苹果, 橘子, 桃子]
arr.addAll(["西瓜","草莓"]); print(arr); //[香蕉, 苹果, 橘子, 桃子, 西瓜, 草莓]
print(arr.indexOf("苹果"));  //1 //indexOf查找不到的话,返回-1;查找到的话,返回索引值
arr.remove("西瓜"); print(arr); //[香蕉, 苹果, 橘子, 桃子, 草莓]
arr.removeAt(3); print(arr); //[香蕉, 苹果, 橘子, 草莓]
arr.fillRange(1, 2, "aaa"); //修改
print(arr); //[香蕉, aaa, 橘子, 草莓] 
arr.insert(2, "bbb"); //插入
print(arr); //[香蕉, aaa, bbb, 橘子, 草莓] 
arr.insertAll(1, ["123","456"]); //插入多个
print(arr); //[香蕉, 123, 456, aaa, bbb, 橘子, 草莓]
var arr = ["香蕉","苹果","橘子"]; var str = arr.join("-"); //List转换成字符串
print(str); //香蕉-苹果-橘子
var newArr = str.split("-"); //字符串转换成List
print(newArr); //[香蕉, 苹果, 橘子] 

forEach:循环遍历

List arr = ["香蕉","苹果","橘子"]; arr.forEach((value){ print(value); });

map:经常使用于修改集合里的数据

//循环遍历修改List
List myNum = [1,3,5]; List newNum = new List(); for(var i = 0; i < myNum.length; i++){ newNum.add(myNum[i]*2); } print(newNum); //[2, 6, 10] //能够用map来实现
List myNum = [1,3,5]; var newNum = myNum.map((value){ return value*2; }); print(newNum.toList()); //[2, 6, 10]

where:把知足条件的返回一个新的集合

List myNum = [1,3,4,5,7,8,9]; var newNum = myNum.where((value){ return value > 5; }); print(newNum.toList()); //[7, 8, 9]

any和every:判断List里有没有知足条件的,有的话返回true或false

//any
List myNum = [1,3,4,5,7,8,9]; var f = myNum.any((value){ //只要集合里有知足条件的就返回true
    return value >5; }); print(f); //true //every
List myNum = [1,3,4,5,7,8,9]; var f = myNum.every((value){ //集合里面每个都要知足条件返回true,不然返回false
    return value >5; }); print(f); //false

(5)Map类型

Map经常使用属性:

keys    获取全部的key值
values    获取全部的value值
isEmpty    是否为空
isNotEmpty     是否不为空


var person = { "name":"张三", "age":20, "sex":"", }; print(person.keys.toList()); //[name, age, sex]
print(person.values.toList()); //[张三, 20, 男]
print(person.isEmpty); //fales
print(person.isNotEmpty); //true

Map经常使用方法:

remove(key) 删除指定key的数据
addAll({...}) 合并映射 给映射增长属性
containsValue 查看映射内的值 返回true/false
forEach
map
where
any
every






var person = { "name":"张三", "age":20, "sex":"", }; person.addAll({"work":["程序员","外卖员"],"height":170}); print(person); //{name: 张三, age: 20, sex: 男, work: [程序员, 外卖员], height: 170}
person.remove("sex"); print(person); //{name: 张三, age: 20, work: [程序员, 外卖员], height: 170}
print(person.containsValue("张三")); //true

forEach():

var person = { "name":"张三", "age":20, "sex":"", }; person.forEach((key,vlaue){ print("$key--$vlaue"); }); //若是是一行代码也能够用=>
person.forEach((key,vlaue)=>print("$key--$vlaue"));

Map类型将key和value关联在一块儿,也就是键值对。像其余支持Map的编程语言同样,key必须是惟一的。

var week = { "Monday" : "星期一", "Tuesday" : "星期二", "Wednesday" : "星期三", "Thursday" : "星期四", "Friday" : "星期五", "Saturday" : "星期六", "Sunday" : "星期日", };
print(week["Monday"]);
//也可使用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),代码以下:

var week = new Map(); week['Monday'] = "星期一"; week['Tuesday'] = "星期二"; week['Wednesday'] = "星期三"; week['Thursday'] = "星期四"; week['Friday'] = "星期五"; week['Saturday'] = "星期六"; week['Sunday'] = "星期日"; week['0'] = '星期一'; print(week); //{Monday: 星期一, Tuesday: 星期二, Wednesday: 星期三, Thursday: 星期四, Friday: 星期五, Saturday: 星期六, Sunday: 星期日, 0: 星期一}
    print(week.length); //8

(6)Set:表示对象的集合,其中每一个对象只能出现一次。

Set:用它最主要的功能就是去除数组重复内容
Set是没有顺序且不能重复的集合,因此不能经过索引去获取值

var ss = new Set(); ss.add("香蕉"); ss.add("苹果"); ss.add("香蕉"); print(ss); //{香蕉, 苹果}
print(ss.toList()); //[香蕉, 苹果]

var arr = new List(); arr.add("香蕉"); arr.add("苹果"); arr.add("香蕉"); print(arr); //[香蕉, 苹果, 香蕉] 

var arr = ["香蕉","苹果","橘子","香蕉","苹果","香蕉","苹果"]; var ss = new Set(); ss.addAll(arr); print(ss.toList()); //[香蕉, 苹果, 橘子]
Set也能够用forEach()循环遍历:
var ss = new Set(); ss.addAll([11,22,333]); ss.forEach((value){ print(value); }); //若是只有一行代码能够用=>
ss.forEach((value)=>print(value));

is 关键词来判断类型:

//加入str是后台返回的数据,不知道是什么类型,能够用is来判断
var str = '1234'; if(str is String){ print('是string类型'); }else if(str is int){ print('是int类型'); }else{ print('是其余类型'); } //是string类型

Dart类型转换:

(1)Number类型转换为String类型:toString()

var myNum = 123; var str = myNum.toString(); print(str is String);  //true

(2)String类型转换为Number类型:parse()

String str = "123"; var myNum = double.parse(str); //String类型转换Number类型的时候建议用double,用int的话,若是有小数会报错 print(myNum is double);  //true

(3)其余类型转换成Boolean类型

isEmpty:判断字符串是否为空 

var str = 'xxx'; if(str.isEmpty){ print('str为空'); }else{ print('str不为空'); } //str不为空
var myNum1 = 0/0; if(myNum1.isNaN){ print('NaN'); }else{ print(myNum1); } //NaN 

var myNum2 = 1; if(myNum2.isNaN){ print('NaN'); }else{ print(myNum2); } //1

三、函数

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语句

(5)箭头函数

只有一条语句的时候能够用箭头函数:

List arr = ["香蕉","苹果","橘子"]; arr.forEach((value){ print(value); }); //箭头函数
arr.forEach((value)=>print(value));

例子1:修改数组里的数据,大于2的值乘以2

List myNum = [1,2,3,4,5]; var newNum = myNum.map((value){ if(value > 2){ return value*2; } return value; }); print(newNum.toList()); //用箭头函数实现
List myNum = [1,2,3,4,5]; var newNum2 = myNum.map((value) => value>2 ? value*2 : value); print(newNum2.toList());

例子2:定义一个方法isEvenNumber来判断一个数是不是偶数,定义一个方法打印1到n之间的偶数。

//定义一个方法isEvenNumber来判断一个数是不是偶数
bool isEvenNumber(int n){ if(n%2 == 0){ return true; } return false; } //打印1到n之间的偶数
printNum(int n){ for(var i = 1; i <= n; i++){ if(isEvenNumber(i)){ print(i); } } } printNum(10); //2 4 6 8 10

四、运算符

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
var a = 10; var b = a++; //先把a的值赋值给b,而后在自增,因此b=10,a=11
print(a); //11
print(b); //10

var a = 10; var b = ++a; //先进行自增,而后再赋值给b,因此都是11
print(a); //11
print(b); //11

注意:在赋值运算里,若是++或--写在前面,这时先运算,再赋值;若是++或--写在后面的时候,先赋值再进行运算。

(2)关系运算符

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

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

int a = 5; int b = 3; print(a==b); //false
    print(a!=b); //true
    print(a>b); //true
    print(a<b); //false
    print(a>=b); //true
    print(a<=b); //false

(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对象,则第一段代码不会作出任何事情,第二段代码会报错。

is 类型判断:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user = new User("张三",20); if(user is User){ //判断user这个对象是否属于User这个类
    user.name = "李四"; } user.printInfo(); //李四----20
}

as 类型转换:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ var user = ''; user = new User("张三",20); //老版本 user.printInfo(); 不会执行,由于不知道user属于什么类型 //因此user用as强制转换为User类型
  (user as User).printInfo(); //张三----20
}

? 条件运算符:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user1 ; user1?.printInfo(); //?表示若是对象是空的话不会调用这个方法
 User user2 = new User("张三",20); user2?.printInfo(); //张三----20 //?判断非空调用方法
}

 

(4)赋值操做符

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

//赋值给a
a = value;
c = a + e;
//若是b为空,则将值分配给b;不然b保持不变 b??= value; //例如
int b = 10;
b??= 20;
print(b); //10 由于b不为空,因此b的值仍是10 //例如
int b;
b??= 20;
print(b); //20





复合赋值运算符:

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

复合赋值符 等式表达式
a op b a = a op b
a += b a = a + b
a -= b a = a - b
var a = 3; a += 5; print(a); //8

(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;
//例如 var a = true ? 123 : 456;

第二种以下表示,若是expr1为非空,则返回其值;不然,计算并返回expr2的值。

expr1 ?? expr2;
//例如
var a;
var b = a ?? 10;
print(b); //a为空,计算并返回expr2的值10赋给b
//例如
var a = 22;
var b = a ?? 10; print(b); //a不为空,返回a的值22赋给b




(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。

还用前面的例子:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user = new User("张三",20); uesr.printInfo(); //张三----20
  user.name = "李四"; user.age = 30; user.printInfo(); //李四----30 //上面的三行代码能够简写为
  user..name = "李四" ..age = 30 ..printInfo(); //李四----30
}

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

五、流程控制语句

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(循环)

//打印出0-50的偶数
for(var i = 0; i <= 50; i++){ if(i%2 == 0){ print(i); } }
//求1到100的和
var sum = 0; for(var i = 0; i <= 100; i++){ sum += i; } print(sum); //5050 //计算5的阶乘 1*2*3*4*5
var sum = 1; for(var i = 1; i <= 5; i++){ sum *= i; } print(sum); //120
//打印List里的内容
List arr = ['张三','李四','王五']; for(var i = 0; i < arr.length; i++){ print(arr[i]); } 
//也能够用for-in实现
List arr = ['张三','李四','王五']; for(var item in arr){ print(item); } 
//打印List里的内容
List arr = [ {"title":"新闻1"},{"title":"新闻2"},{"title":"新闻3"}, ]; for(var i = 0; i < arr.length; i++){ print(arr[i]["title"]); }
//打印List里的内容
List arr = [ { "card":"国内", "news":[ {"title":"国内新闻1"},{"title":"国内新闻2"},{"title":"国内新闻3"} ] }, { "card":"国际", "news":[ {"title":"国际新闻1"},{"title":"国际新闻2"},{"title":"国际新闻3"} ] }, ]; for(var i = 0; i < arr.length; i++){ print(arr[i]["card"]); for(var j = 0; j < arr[i]["news"].length; j++){ print(arr[i]["news"][j]["title"]); } }

下面举例说明,首先定义了一个字符串“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
//打印0到10
var i = 0; while(i <= 10){ print(i); i++; } //打印1到100的和
var sum = 0; var i = 1; while(i <= 100){ sum += i; i++; } print(sum); //5050 //do-while实现
var sum = 0; var i = 1; do{ sum += i; i++; }while(i <= 100); print(sum); //5050

while和do-while的区别:

while:先判断第一次循环条件,不成立的状况下,不执行语句;

do-while:先执行一次语句,再判断第一次循环条件。

注意:死循环的问题。

(4)break和continue:

break能够用在switch case中,也能够用在for循环和while循环中。

break语句功能:
①、在switch语句中使流程跳出
②、在循环语句中使流程跳出当前循环,遇到break循环终止,后面代码也不会再执行;在多层循环中,一个break语句只能向外跳一层



continue能够用在for循环以及while循环中,可是不建议用在while循环里,不当心容易形成死循环。

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”
//continue例子
for(var i = 0; i <=10; i++){ if( i == 4){ continue; //跳出本次循环体,继续下面的循环
 } print(i); } //0 1 2 3 5 6 7 8 9 10 //若是i等于4跳出循环
for(var i = 0; i <=10; i++){ if( i == 4){ break; } print(i); } //0 1 2 3 //break跳出一层循环
for(var i = 0; i < 3; i++){ print("外层---$i"); for(var j = 0; j < 3; j++){ if(j == 1){ break; } print("里层$j"); } } //外层---0 //里层0 //外层---1 //里层0 //外层---2 //里层0

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

六、方法

(1)自定义方法

自定义方法基本格式:

返回类型 方法名称(参数1,参数2...){ 方法体 return 返回值; }
//定义方法
void printInfo(){ //void 是没有返回值的
    print("我是一个自定义方法"); } //运行方法
printInfo();
int getNum(){ //int是方法的返回值类型
    var myNum = 123; return myNum; } var n = getNum(); //调用方法,并发返回值赋给n
print(n); //123
 String printInfo(){ return 'This is string'; } var str = printInfo(); print(str); //This is string
 List getList(){ return ["aa","bb","cc"]; } print(getList()); //[aa, bb, cc]

调用方法传参:

例子1:定义一个方法,求1到这个数的全部的和

int sumNum(n){ var sum = 0; for(var i = 0; i <= n; i++){ sum += i; } return sum; } print(sumNum(10)); //55
print(sumNum(100)); //5050

例子2:定义一个打印用户信息的方法

String printUserInfo(String name, int age){ //形参
    return "姓名:$name--年龄:$age"; } print(printUserInfo("张三",20)); //实参

例子3:定义一个带可选参数的方法

String printUserInfo(String name, [int age]){ //[]可选参数
    if(age != null){ return "姓名:$name--年龄:$age"; } return "姓名:$name--年龄:保密"; } print(printUserInfo("张三")); print(printUserInfo("李四",20));

例子4:定义一个带默认参数的方法

String printUserInfo(String name, [int age, String sex = ""]){ if(age != null){ return "姓名:$name--年龄:$age--性别:$sex"; } return "姓名:$name--年龄保密--性别:$sex"; } print(printUserInfo("张三")); //姓名:张三--年龄保密--性别:男 
print(printUserInfo("李四",20)); //姓名:李四--年龄:20--性别:男
print(printUserInfo("王五",20,"")); //姓名:王五--年龄:20--性别:女 //有个问题,若是实现只写名字和性别会报错,不能中间空一项,必须三项都写

例子5:定义一个命名参数的方法

//用命名参数{}不会出现上面问题,不过实参要写上key
String printUserInfo(String name, {int age, String sex = ""}){ if(age != null){ return "姓名:$name--年龄:$age--性别:$sex"; } return "姓名:$name--年龄保密--性别:$sex"; } print(printUserInfo("张三")); //姓名:张三--年龄保密--性别:男 
print(printUserInfo("李四",age:20)); //姓名:李四--年龄:20--性别:男
print(printUserInfo("王五",sex:"")); //姓名:王五--年龄保密--性别:女

例子6:实现一个把方法当作参数的方法

//把fn1赋值给了fn,而后调用fn2执行里面的fn,打印出里面的“String” 
fn1(){ print("String"); } fn2(fn){ fn(); } //调用fn2方法,把fn1方法当作参数传入
fn2(fn1); //fn1 //更好理解
var fn = (){ print("我是一个匿名方法"); }; fn();

(2)匿名方法

var printNum = (int n){ print(n+2); }; printNum(3); //5

(3)自执行方法

格式:

((){ ... })(); //或者
(){ ... }();

例子:

((n){ print(n); })(12); //12

(4)方法的递归

例子1:经过方法的递归求5的阶乘

var sum = 1; fn(n){ sum *= n; if(n == 1){ return; } fn(n-1); } fn(5); print(sum); //120

例子2:经过方法的递归求1到100的和

var sum = 0; fn(n){ if(n == 0){ return; } sum += n; fn(n-1); } fn(100); print(sum); //5050

(5)闭包

闭包的写法:函数嵌套函数,并return里的函数,这样就造成了闭包

想实现的功能:常驻内存、不污染全局

fn(){ var a = 123; //不会污染全局,常驻内存
    return(){ a++; print(a); }; } var b = fn(); b(); //124
b(); //125
b(); //126

七、异常处理

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

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是堆栈跟踪信息
//例如 
String str = ""; try{ var myNum = double.parse(str); print(myNum is double); }catch(e){ print(0); } //str为空,因此转换Number类型失败,打印0

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

八、面向对象 (面向对象的三大特性:封装、继承、多态)

Dart做为高级语言支持面向对象的不少特性,而且支持基于mixin的继承方式。基于mixin的继承方式是指:一个类能够继承自多个父类,至关于其余语言里的多继承。全部的类都有同一个基类Object,这个特性相似于Java语言,Java全部的类也都是继承自Object,也就是说一切皆为对象。全部的对象都是类的实例,而且全部的类都是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; }
class User{ String name = "张三"; int age = 20; void getInfo(){ //print("$name----$age");
        print("${this.name}----${this.age}"); } void setInfo(int age){ this.age = age; } } void main(){ //实例化
    var user = new User(); //也能够指定类型 User user = new User();
    print(user.name); //张三
    user.getInfo(); //张三----20
    user.setInfo(25); user.getInfo(); //张三----25
}

私有属性、私有方法:

私有属性:私有属性须要单独一个文件才可使用

例子:新建Animal.dart文件

Animal{ String _name; //私有属性
    int age; Animal(this._name, this.age); }

在main.dart文件里引入Animal.dart文件

import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由于_name是私有属性,因此会报错
   print(a.age); //3
}

利用公有方法访问私有属性 

仍是上面的例子:

Animal{ String _name; //私有属性
    int age; Animal(this._name, this.age); //公有方法
 String getName(){ return this._name; } } 
import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由于_name是私有属性,因此会报错
   print(a.age); //3
   print(a.getName()); //小狗
}

私有方法也是同理,能够经过公有方法间接的访问私有方法:

Animal{ String _name; //私有属性
    int age; Animal(this._name, this.age); //私有方法
    void _run(){ print("这是个私有方法"); } getRun(){ this._run(); //类里面方法的相互调用
 } }
import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由于_name是私有属性,因此会报错
   print(a.age); //3
   print(a.getName()); //小狗 //间接的调用私有方法
   a.getRun(); //这是一个私有方法
}

静态属性、静态方法:静态方法不能访问非静态成员,非静态方法能够访问静态成员以及非静态成员

例子:

class User{ static String name = "张三"; int age = 20; static void show(){ //静态方法
 print(name); print(this.age); //报错,静态方法不能够访问非静态成员
 } void printInfo(){ //非静态方法能够访问静态成员以及非静态成员
        print(name); //访问静态属性
        print(this.age); //访问非静态属性
        show(); //调用静态方法
 } } void main(){ //静态属性和方法不用实例化,能够直接调用
    print(User.name); //张三
    User.show(); //张三
    User user = new User(); //非静态属性和方法须要实例化
    user.printInfo(); //张三 //20 //张三
}

(2)构造函数

①默认构造函数

class User{ String name = "张三"; int age = 20; //默认构造函数
 User(){ print("这是构造函数里面的内容,这个方法在实例化的时候触发"); } } main(){ //实例化
    User user = new User(); //运行,自动打印出:这是构造函数里面的内容,这个方法在实例化的时候触发
}

②常规构造函数

构造函数是用来构造当前类的函数,是一个特殊的函数,函数名称必需要和类名相同才行。以下代码为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); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user1 = new User("张三", 20); user1.printInfo(); //张三----20 
   User user2 = new User("李四", 25); user2.printInfo(); //李四----25 
}

③命名的构造函数

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

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

例子:

class User { String name; int age; User(this.name, this.age); //命名构造函数,能够多个
 User.now(){ print("我是命名构造函数"); } User.setInfo(String name, int age){ this.name = name; this.age = age; } void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ //调用命名构造函数
    User user1 = new User.now(); //我是命名构造函数
    User user2 = new User.setInfo("李四",30); user2.printInfo(); //李四----30
}

通常把类单独离成一个模块(一个dart文件),使用的时候引入这个dart文件就能够了。

④构造函数初始化列表(先赋值再执行构造函数)

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

class User { final String name; final int age; User(name, age) : name = name, age = age; } main() { var p = new User('张三', 20); }

例子:

class Rect{ num height; num width; Rect():height=2, width=10{ print("${this.height}----${this.width}"); } getArea(){ return this.height * this.width; } } void main(){ Rect r = new Rect(); print(r.getArea()); } //2----10 //20

(3)读取和写入对象

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

get例子:

class Rect{ num height; num width; Rect(this.height,this.width); area(){ return this.height * this.width; } } void main(){ Rect r = new Rect(10, 4); print("面积:${r.area()}"); //面积:40
} //使用get
class Rect{ num height; num width; Rect(this.height,this.width); get area{ return this.height * this.width; } } void main(){ Rect r = new Rect(10, 4); print("面积:${r.area}"); //面积:40 //注意调用直接经过访问属性的方式访问area
}

set例子:

class Rect{ num height; num width; Rect(this.height,this.width); get area{ return this.height * this.width; } set areaHeight(value){ this.height = value; } } void main(){ Rect r = new Rect(10, 4); r.areaHeight = 6; print("面积:${r.area}"); //面积:24
}

例如,定义一个矩形的类,有上、下、左、右四个成员变量: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关键字来制定父类。

Dart中的类的继承:
①子类使用extends关键词来继承父类
②子类会继承父类里面可见的属性和方法,可是不会继承构造函数
③子类能复写父类的方法 getter 和 setter


例子1:子类继承父类

class User{ String name = "张三"; num age = 20; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ //Web类继承User类里面可见的属性和方法
 } void main(){ Web w = new Web(); print(w.name); //张三
  w.printInfo(); //张三----20
}

例子2:实例化子类的时候给父类传参,经过super来实现

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ //Web类的构造函数:初始化列表
  Web(String name, num age) : super(name, age){ //执行子类的构造函数以前,把子类里面的传过来的参数赋值给父类

}
} void main(){ Web w new Web("张三",12); w.printInfo(); //张三----12 }

例子3:子类里能够定义本身的属性和方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ String sex; //Web类的构造函数:初始化列表
 Web(String name, num age, String sex) : super(name, age){ this.sex = sex; } run(){ print(("${this.name}----${this.age}----${this.sex}"); } } void main(){ Web w = new Web("张三",12,""); w.printInfo(); //张三----12
  w.run(); //张三----12----男
}

例子4:给父类的命名构造函数传参

class User{ String name; num age; User(this.name,this.age); User.xxx(this.name,this.age); //命名构造函数
  void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ String sex; //Web类的构造函数:初始化列表
  Web(String name, num age, String sex) : super.xxx(name, age){ //给命名的构造函数传参
    this.sex = sex; } run(){ print(("${this.name}----${this.age}----${this.sex}"); } } void main(){ Web w = new Web("张三",12,""); w.printInfo(); //张三----12
  w.run(); //张三----12----男
}

例子5:子类里直接调用父类方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } work(){ print("${this.name}在公做..."); } } class Web extends User{ Web(String name, num age) : super(name, age){ } run(){ print(("run"); super.work(); //子类直接调用父类的方法 也能够经过this
 } } void main(){ Web w = new Web("李四",20); w.run(); //run //李四在公做...
}

例子6:子类里复写父类的方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } work(){ print("${this.name}在公做..."); } } class Web extends User{ Web(String name, num age) : super(name, age){ } run(){ print(("run"); } //复写父类的方法 和父类的方法名字同样
  @override //复写父类方法的时候建议写上
  void printInfo(){ print("姓名:${this.name}----年龄:${this.age}"); } @override work(){ print("${this.name}的工做是写代码"); } } void main(){ Web w = new Web("李四",20); w.printInfo(); //姓名:李四----年龄:20
  w.work(); //李四的工做是写代码
}

例子:定义一个动物类,动物具备吃和跑两种能力。再定义一我的类,人类是属于动物类的,人类不只会吃和会跑,还会说、会学习。因此人类至关于动物类的一个扩展。具体代码:

//动物类
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语言中的接口。抽象类里不具体实现方法,只是写好定义接口,具体实现留着调用的人去实现。

Dart中的抽象类:Dart抽象类主要用于定义标准,子类能够继承抽象类,也能够实现抽象类接口。

①.抽象类经过abstract关键字来定义
②.Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法咱们称为抽象方法
③.若是子类继承抽象类,必须实现里面的抽象方法
④.若是把抽象类当作接口实现的话,必须得实现抽象类里面定义的全部属性和方法。
⑤.抽象类不能被实例化,只有继承它的子类能够



例子:定义一个Animal类,要求它的子类必须包含eat方法

abstract class Animal{ //abstract定义抽象类
  eat(); //抽象方法 没有方法体的方法咱们称为抽象方法
  run(); //抽象方法
  printInfo(){ //非抽象方法 普通方法
    print("我是一个抽象类里面的普通方法"); } } class Dog extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小狗在吃骨头"); } @override run(){ print("小狗在跑"); } } class Cat extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小猫在吃鱼"); } @override run(){ print("小猫在跑"); } } void main(){ Dog dog = new Dog(); dog.eat(); //小狗在吃骨头
  Cat cat = new Cat(); cat.eat(); //小猫在吃鱼
  var a = new Animal(); //报错,Animal是抽象类无法直接被实例化 //抽象类不能被实例化,只有继承它的子类能够
  cat.printInfo(); //我是一个抽象类里面的普通方法
}

例子:定义一个抽象类叫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)接口:

首先,dart的接口没有interface关键字定义接口,而是普通类或抽象类均可以做为接口被实现。
一样使用implements关键字进行实现接口。
可是dart的接口有点奇怪,若是实现的类是普通类,会将普通类和抽象类中的属性的方法所有须要复写一遍。
而由于抽象类能够定义抽象方法,普通类不能够,因此通常若是要实现像Java接口那样的方式,通常会使用抽象类。
建议使用抽象类定义接口。



例子:定义一个DB库,支持mysql、mssql、mongodb,这三个类里面都有一样的方法。

abstract class Db{ //abstract定义抽象类 当作接口 接口就是约定、规范
  String url; //数据库的连接地址
 add(String data); edit(); delete(); } class Mysql implements Db{ //implements来实现接口Db
 @override String url; Mysql(this.url); @override add(String data){ print("这是mysql的add方法" + data); } @override edit(){ } @override delete(){ } } class Mssql implements Db{ //implements来实现接口Db
 @override String url; @override add(String data){ print("这是mssql的add方法" + data); } @override edit(){ } @override delete(){ } } void main(){ Mysql mysql = new Mysql("http://xxx"); mysql.add("12345"); //这是mysql的add方法12345
}

能够把以上代码分离成3个dart文件,方便想用谁就能够引用谁。

Db.dart

abstract class Db{ //abstract定义抽象类 当作接口 接口就是约定、规范
  String url; //数据库的连接地址
 add(String data); edit(); delete(); }

Mysql.dart

impor "Db.dart"; class Mysql implements Db{ //implements来实现接口Db
 @override String url; Mysql(this.url); @override add(String data){ print("这是mysql的add方法" + data); } @override edit(){ } @override delete(){ } } 

Mssql.dart

import "Db.dart"; class Mssql implements Db{ //implements来实现接口Db
 @override String url;
Mssql(this.url); @override add(String data){ print(
"这是mssql的add方法" + data); } @override edit(){ } @override delete(){ } }

使用那个就引用:

import "Mysql.dart"; import "Mssql.dart"; void main(){ Mysql mysql = new Mysql("http://xxx"); mysql.add("12345"); //这是mysql的add方法12345
  Mssql mssql = new Mssql(); mssql.url = "http://xxx"; mssql.add("增长的数据"); //这是这是mssql的add方法增长的数据
}

extends抽象类和implements的区别:
①.若是要复用抽象类里面的方法,而且要用抽象方法约束子类的话,咱们就用extends继承抽象类
②.若是只是把抽象类当作标准的话,咱们就用implements实现抽象类。

例子:Dart中一个类实现多个接口:

abstract class A{ //abstract定义抽象类A 当作接口
 String name; printA(); //抽象方法
} abstract class B{ //abstract定义抽象类B 当作接口
      printB(); //抽象方法
} class C implements A,B{ //implements来实现接口A,B,实现全部属性和方法
 @override String name; @override printA(){ print("printA"); } @override printB(){ } } void main(){ C c = new C(); //实例化C
      c.printA(); //printA
}

(8)Dart中的多态:

容许将子类类型的指针赋值给父类类型的指针,同一个函数调用会有不一样的执行效果。
子类的实例赋值给父类的引用。
多态就是父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不一样的表现。

例子:这个就是多态

abstract class Animal{ //abstract定义抽象类
  eat(); //抽象方法 父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不一样的表现。
} class Dog extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小狗在吃骨头"); } } class Cat extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小猫在吃鱼"); } } void main(){ Dog dog = new Dog(); dog.eat(); //小狗在吃骨头
  Cat cat = new Cat(); cat.eat(); //小猫在吃鱼
}

例子:也是多态,若是子类只能运行父类里定义的方法

abstract class Animal{ //abstract定义抽象类
  eat(); //抽象方法 父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不一样的表现。
} class Dog extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小狗在吃骨头"); } run(){ print("run"); } } class Cat extends Animal{ //若是子类继承抽象类,必须实现里面的抽象方法
 @override eat(){ print("小猫在吃鱼"); } run(){ print("run"); } } void main(){ Animal dog = new Dog(); //表示把子类的实例赋值给了父类的一个引用,不能在调用run方法,只能调用父类定义的方法
  dog.eat(); //小狗在吃骨头
  Animal cat = new Cat(); cat.eat(); //小猫在吃鱼
}

(9)枚举类型

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

enum Color { red, green, blue }

获取枚举类中全部的值,使用value经常使用:

List<Color> 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
}

(10)Mixins:中文意思是混入,就是在类中混入其余功能,实现相似多继承的功能。

Mixins(混入功能)至关于多继承,也就是说能够继承多个类。使用with关键字来实现Mixins的功能。

由于mixins使用的条件,随着Dart版本一直在变,这里讲的是Dart2.x中使用mixins的条件:
①.做为mixins的类只能继承自Object,不能继承其余的
②.做为mixins的类不能有构造函数
③.一个类能够mixins多个mixins类
④.mixins毫不是继承,也不是接口,而是一种全新的特性



例子1:

class A{ String info = "this is A"; void printA(){ print("A"); } } class B{ void printB(){ print("B"); } } class C with A,B { //混入 C类继承A类和B类的属性和方法
 } void main(){ var c = new C(); c.printA(); //A
    c.printB(); //B
    print(c.info); //this is A
}

例子2:

class User{ String name; num age; User(this.name,this.age);//构造函数
 printInfo(){ print("${this.name}----${this.age}"); } void run(){ print("User run"); } } class A{ String info = "this is A"; void printA(){ print("A"); } void run(){ print("A run"); } } class B{ void printB(){ print("B"); } void run(){ print("B run"); } } class C extends User with A,B { //即继承User又混入A,B
      C(String name, num age):super(name,age); //父类里有构造函数并传参的话,子类也要写构造函数
 } void main(){ var c = new C("张三",20); c.printInfo(); //张三----20
      c.run(); //B run //一样的run方法,后面的把前面的覆盖了
}

示例代码以下:

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

Mixins的实例类型是其超类的子类型:

class A{ String info = "this is A"; void printA(){ print("A"); } } class B{ void printB(){ print("B"); } } class C with A,B { } void main(){ var c = new C(); print(c is A); //true A和B就是C的超类
    print(c is B); //true
}

九、泛型:就是解决类、接口、方法的复用性,以及对不特定数据类型的支持(类型校验)

泛型一般是为了类型安全而设计的,适当地指定泛型类型会生成更好的代码,可使用泛型来减小代码重复。Dart中使用<T>的方式来定义泛型。

例子:传入什么类型,返回什么类型的数据

T getData<T>(T value){ //T表明泛型,能够是任意字母
    return value; } //也能够这样写,对传入参数进行校验,不对返回参数校验
getData<T>(T value){ return value; } void main(){ print(getData<int>(12)); //12
}

例如,若是想要List只包含字符串,能够将其声明为list<String>。以下所示:

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

(1)用于集合类型

泛型用于List和Map类型参数化:List:<type>      Map:<keyType, valueType>

例子:

List list = new List<String>(); list.add('你好'); list.add('你们好'); print(list); //[你好, 你们好]
 List list2 = new List<int>(); list2.add(11); list2.add(22); print(list2); //[11, 22]

例子:

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

例子:把下面类转换成泛型类,要求List里面能够增长int类型的数据,也能够增长String类型的数据。

class PrintClasee<T>{ List list = new List<T>(); void add(T value){ this.list.add(value); } void printInfo(){ for(var i = 0; i < this.list.length; i++){ print(this.list[i]); } } } void main(){ PrintClasee p = new PrintClasee<String>(); p.add("你好"); p.add("你们好"); p.printInfo(); //你好 //你们好
 PrintClasee p2 = new PrintClasee<int>(); p2.add(12); p2.add(33); p2.printInfo(); //12 //33
}

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

Map类型的例子以下:

var users = new Map<String, String>();

(3)泛型接口

实现数据缓存的功能:有文件缓存和内存缓存,文件缓存和内存缓存按照接口约束实现
①.定义一个泛型接口,约束实现它的子类必须由getByKey(key)和setByKey(key,value)
②.要求setByKey时候的value的类型和实例化子类时候指定的类型一致

abstract class Cache<T>{ getByKey(String key); void setByKey(String key, T value); } class FileCache<T> implements Cache<T>{ //文件缓存
 @override getByKey(String key){ return null } @override void setByKey(String key, T value){ print("我是文件缓存 把key=${key} vlaue=${value} -写入文件中"); } } class MemoryCache<T> implements Cache<T>{ //内存缓存
 @override getByKey(String key){ return null } @override void setByKey(String key, T value){ print("我是内存缓存 把key=${key} vlaue=${value} -写入内存中"); } } void main(){ MemoryCache m = new MemoryCache<String>(); m.setByKey("index","首页数据"); //我是内存缓存 把key=index vlaue=首页数据 -写入内存中
 MemoryCache map = new MemoryCache<Map>(); map.setByKey("index",{"name":"张三","age":20}); //我是内存缓存 把key=index vlaue={"name":"张三","age":20} -写入内存中
}

十、库的使用

Dart中的库主要有三种:
①.咱们自定义的库,好比import "lib/xx.dart";
②.系统内置库,好比import "dart:io";
③.Pub包管理系统中的库,好比import "package:dio/dio.dart"; (须要在pubspec.yaml文件里添加依赖)


(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;

十一、异步支持

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(); //其余处理
}

十二、元数据 

使用元数据给代码添加更多的信息。元数据是以@开始的修饰符,在@后面接着编译时的常量或调用一个常量构造函数。目前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(变量声明)。

1三、注释

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

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

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

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

相关文章
相关标签/搜索