Dart简述
Dart是谷歌开发的一门编程语言,在Dart中所有的东西都是对象。
变量和类型
在Dart中,声明变量使用var关键字:
var name = '小张';
在Dart语言里一切皆为对象,如果没有将变量初始化,那么它默认为null。
常量和固定值
常量和固定值在开发中很常用,如果第一的变量不会变化,可以使用final或const来指明。其中,const是一个编译时的常量,final的值只能被设定一次。
// 定义一个常量
final username = '张三';
const pi = 3.1415926;
Dart语言常用的基本数据类型包括:Number、String、Boolean、List、Map。
函数
Dart是一个面向对象的语言,所以函数也是对象,函数属于Function对象。函数可以像参数一样传递给其他函数,这样便于做回调处理。
Flutter应用必须要有一个main函数和其他语言一样作为程序的入口函数。
void main => runApp(MyApp());
在Dart语言中,函数的返回值包含如下特点:
所有的函数都会有返回值。
如果没有指定函数返回值,则默认的返回值是null。
没有返回值的函数,系统会在最后添加隐式的return语句。
- 可选参数
将参数使用中括号[]括起来,用来表示是可选位置参数。
// 获取用户信息
String getUserInfo(String name, String sex, [String from]){
var info = '$name的性别是$sex';
if(from != null) {
info = '$info来自$from';
}
return info;
}
void test(){
print(getUserInfo('小王', '男'));
}
参数默认值
如果参数指定了默认值,当不传入值时,函数会使用这个默认值。如果传入值则用传入的值取代默认值。
// 获取用户信息
String getUserInfo(String name, String sex, [String from = '中国']){
var info = '$name的性别是$sex';
if(from != null) {
info = '$info来自$from';
}
return info;
}
void test(){
print(getUserInfo('小王', '男'));
}
运算符
Dart支持各种类型的运算符,并且其中的一些操作符还能进行重载。
描述 | 运算符 |
---|---|
一元后缀 | expr++ expr-- () [] . ?. |
一元前缀 | -expr !expr ~expr ++expr -- expr |
乘法类型 | * / % ~/ |
加法类型 | + - |
移位运算符 | << >> |
与位运算符 | & |
异或位运算符 | ^ |
或位运算符 | | |
关系和类型测试 | >= <= > < as is is! |
等式 | == != |
逻辑与 | && |
逻辑或 | || |
条件 | expr1 ? expr2 : expr3 |
级联 | .. |
赋值 | = *= /= ~/= %= += -= <<= >>= &= ^= |= ??= |
在上面的表中,操作符的优先级由上到下逐个减少,上面行内的操作符优先级大于下面行内的操作符。
算数运算符
运算符 | 描述 |
---|---|
+ | 加 |
- | 减 |
-expr | 一元运算减 |
* | 乘 |
/ | 除 |
~/ | 除以,返回整数结果 |
% | 获取整数除法的余数(模数) |
Dart 也支持前置和后缀 递增、递减运算符。
比较运算符
运算符 | 描述 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
< | 小于 |
>= | 大于或等于 |
<= | 小于或等于 |
类型检查运算符
使用 as ,is 和 is !运算符可以方便地在运行时检查类型。
运算符 | 描述 |
---|---|
as | Typecast(也用于指定库前缀) |
is | 如果对象具有指定的类型,则为True |
is! | 如果对象具有指定的类型,则返回false |
案例1:下面案例用于检测emp是否是Person类型:
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
案例2:下面案例emp的类型设置为Person类型;
(emp as Person).firstName = 'Bob';
注意:如果emp为null或不是Person,则案例1不执行任何操作,案例2会抛出异常。
赋值运算符
Dart 可以使用 = 运算符赋值。
// 把value 赋值给a
a = value;
// 如果b 为null 把 value 赋值给 b;否则b 保持不变。
b ??= value;
复合赋值运算符:
= |
–= |
/= |
%= |
>>= |
^= |
---|---|---|---|---|---|
+= |
*= |
~/= |
<<= |
&= |
` |
逻辑运算符
运算符 | 描述 |
---|---|
! |
逻辑非 |
` | |
&& |
逻辑或 |
按位运算符合移位运算符
您可以在Dart中操纵数字的各个位。通常,您将使用这些按位和移位运算符和整数。
运算符 | 描述 |
---|---|
& |
按位或 |
` | ` |
^ |
按位异或 |
~expr |
按位取反 |
<< |
左移 |
>> |
右移 |
流程控制语句
Dart的流程控制语句如下:
if 和 else
for(循环)
while 和 do-while(循环)
break 和 case
assert(断言)
try-catch 和 throw
if 和 else
Dart支持if及else的多种组合,示例代码如下:
String today = 'Monday';
if(today == 'Monday'){
print('今天是星期一');
}else if(today == 'Tuesday'){
print('今天是星期二');
}else{
print('今天是个好日子');
}
for循环
下面的示例中将定义的字符串"Hello Dart"使用for循环向message变量中写入5个通用的字符。
var message = new StringBuffer("Hello Dart");
for(var i = 0; i < 5; i++){
message.write('!');
}
print(message);
除了常规的for循环外,针对可以序列化的操作数可以使用forEach()方法。
var arr = {0, 1, 2, 3, 4, 5, 6};
for(var v in arr){
print(v);
}
while和do-while
while循环和do-while循环的区别在于while循环是先循环再执行,而do-while循环是先执行再循环。
var _temp = 0;
while(_temp < 5){
print("这是一个while循环:" + _temp.toString());
_temp++;
}
接下来我们看看do-while循环的示例:
var _temp = 0;
do{
print("这是一个循环:" + _temp.toString());
}while(_temp < 5);
- break 和 contunue
break用来跳出循环,改造前面的循环例子,代码如下:
var arr = {0, 1, 2, 3, 4, 5, 6};
for(var v in arr){
if(v == 2) {
break;
}
print(v);
}
上面的代码当v=2时结束循环,现在我们把break改为continue代码如下所示:
var arr = {0, 1, 2, 3, 4, 5, 6};
for(var v in arr){
if(v == 2) {
continue;
}
print(v);
}
switch 和 case
Dart中switch/case语句使用==操作比较整数、字符串或其他编译过程中的常量,从而实现分支的作用。
String today = 'Monday';
switch(today){
case 'Monday':
print('星期一');
break;
case 'Tursday':
print('星期二');
break;
}
assert
Dart语言通过使用assert语句来中断正常的执行流程,当assert判断的条件为false时发生中断。
如果assert的判断为true,则继续执行下面的语句;反之则会抛出一个断言错误异常AssertionError。
// 确定变量的值不为null
assert(text != null);
异常处理
异常是表示发生了意外的错误,如果没有捕获异常,则会引发异常的隔离程序被挂起,并且程序将被终止。
Dart可以抛出并捕获异常,但是与Java相反,Dart的所有异常都是未检查的异常。
抛出异常
下面是一个抛出或引发异常的示例:
throw FormatException('抛出一个FormatException异常');
捕获异常
可以指定一个或两个参数来捕获异常,第一个是抛出异常,第二个是堆栈跟踪。
try{
// ...
}on Exception catch(e){
print('Exception details:\n $e');
}catch(e, s){
print('Exception details:\n $e');
print('Stack trace:n $s');
}
上面代码第一个catch用来捕获异常详细信息,第二个catch是堆栈跟踪信息。
- Finally
要确保某些代码能够运行,无论是否抛出异常,请使用finally子句。如果没有catch子句匹配异常,则异常在finally子句运行后传播。
try{
// ...
}on Exception catch(e){
print('Exception details:\n $e');
}catch(e, s){
print('Exception details:\n $e');
print('Stack trace:n $s');
}finally{
print('Do some thing:\n');
}
面向对象
Dart作为高级语言支持面向对象的很多特性,并且支持基于mixin的继承方式。(一个类可以继承自多个父类,相当于其他语言中的多继承)。
// 实例化一个User类的对象user
var user = new User('张三', 20);
成员变量
类定义的所有变量都会隐式的定义setter方法,针对非空的变量会额外增加getter方法。实例化成员变量的代码如下:
class User{
String name; // name成员变量
int age; // age成员变量
}
main(){
var user = new User();
user.name = '张三'; // 相当于使用了name的setter方法
user.age = 20;
}
构造函数
1) 常规构造函数
构造函数的用来构造当前类的函数,是一种特殊的函数,函数的名称必须要和类名相同。
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);
}
2) 命名构造函数
使用命名构造函数从另一类或现有的数据中快速实现构造函数,代码如下所示:
class User{
String name;
int age;
User(this.name, this.age);
User.fromJson(Map json){
name = json['name'];
age = json['age'];
}
}
3) 构造函数初始化列表
除了调用父类的构造函数,也可以通过初始化列表在子类的构造函数运行前来初始化的实例成员变量。
class User{
String name;
int age;
User(name, age) : name = name, age = age;
}
main(){
var user = new User('张三', 20);
}
读取和写入对象
get()和set()方法是专门用于读取和写入对象的属性的方法,每一个类的实例都隐式的包含有get()和set()方法。
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;
}
main(){
var rect = new Rectangle(3, 4, 20, 15);
print(' left:’+rect. left. toStr ing ( ) ) ;
print ('right :'+ rect.r ght. 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 值为 so' ) ;
print('top :' + rect.top.toString());
print('bottom:' + rect. bottom. toString ());
}
重载操作
定义一个Vector向量类,编写两个方法分别用于重载加号和减号,当两个向量相加,就表示它们x值和y值相加,反之亦然。
// 定义一个向量类
class Vector{
final int x;
final int y;
const Vector(this.x, this.y);
// 重载加号+
Vector operator +(Vector v){
return new Vector(x + v.x, y + v.y);
}
// 重载减号-
Vector operator -(Vector v){
return 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());
}
}
继承类
继承就是子类继承父类的行为和特征,使得子类对象具有父类的实例域和方法;或子类从父类继承方法,使得子类具有父类相同的行为。
Dart中使用extends关键字来创建一个子类,super关键字来指定父类。
// 动物类
class Animal{
// 动物会吃
void eat(){
print('动物会吃');
}
// 动物会跑
void run(){
print('动物会跑');
}
}
// 人类
class Human extends Animal{
// 人类会说
void say(){
print('人类会说');
}
// 人类会学习
void study(){
print('人类会学习');
}
}
main(){
print('实例化一个动物类');
var animal = new Animal();
animal.eat();
animal.run();
print('实例化一个人类');
var human = new Human();
human.eat();
human.run();
human.say();
human.study();
}
抽象类
抽象类里不具体实现方法,只是定义好接口,具体实现留给调用的人去实现。抽象类可以使用abstract关键字定义。
接下里定义一个抽象类DataBaseOperate类,里面定义四个数据库操作方法“增删改查”,再定义DataBaseOperateImpl类继承自DataBaseOperate来实现抽象类的方法。
// 数据库操作抽象类
abstract class DetaBaseOperate{
void insert();// 插入的方法
void delete(); // 删除的方法
void update(); // 更新的方法
void query(); // 查询的方法
}
// 数据库操作实现类
class DataBaseOperateImpl extends DetaBaseOperate{
// 实现插入的方法
void insert(){
print('实现了插入的方法');
}
// 实现删除的方法
void delete(){
print('实现了删除的方法');
}
// 实现更新的方法
void update(){
print('实现了更新的方法');
}
// 实现查询的方法
void query(){
print('实现了查询的方法');
}
}
main(){
var db = new DataBaseOperateImpl();
db.insert();
db.delete();
db.update();
db.query();
}
枚举类型
枚举类是一种特殊的类,通常用来表示相同类型的一组常量值。每个枚举类型都用于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: // 默认颜色
print(aColor); // 'Color.blue'
}
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<String> args){
T t = new T();
t.a();
t.b();
}
泛型
泛型通常是为了类型安全而设计的,适当地指定泛型类型会生成更好的代码,Dart中使用
- 用于集合类型
泛型用于List和Map类型参数化:
var names = <String>['张三', '李四', '王五'];
var weeks = <String, String>{
'Monday' : '星期一',
'Tuesdat' : '星期二',
'Wednesday' : '星期三',
'Thursdat' : '星期四',
'Friday' : '星期五',
'Saturday' : '星期六',
'Sunday' : '星期日'
};
- 在构造函数中参数化
Map类型的例子如下所示:
var users = new Map<String, User>();
库的使用
1) 引用库
通过import语句在一个库中引用另一个库的文件,需要注意如下事项
在import语句后面需要接上库的文件的路径。
对Dart语言提供的库文件使用dart:xx格式
第三方库文件使用package:xx的格式。
import的例子如下所示:
import 'dart:io';
import 'package:mylib/mylib.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
3) 引用库的一部分
如果只需要使用库的一部分内容,可以有选择的引用,有如下关键字:
show关键字:只引用一点。
hide关键字:除此之外都引用。
示例代码如下所示:
// 导入foo
import 'package:lib1/lib1.dart' show foo;
// 除了foo导入其他所有内容
import 'package:lib2/lib2.dart' hide foo;
代码中第一行只引用lib1.dart下的foo部分,第二行代码引用lib2.dart下的所有内容,除了foo。
异步支持
Dart语言是目前少数几个支持异步操作的语言。一般使用async函数和await表达式实现异步操作。
Dart库提供asynchronous功能,该功能提供接口来进行耗时操作,比如文件读写、网络请求等。该功能返回Future或Stream对象。
可以通过如下的方式来获取asynchronous功能返回的Future对象的值:
使用async函数和await表达式。
使用Future功能提供的API。
可以通过如下的方式来获取asynchronous功能返回的Stream对象的值:
await readFile()
必须在一个使用了async关键字标记后的函数中使用await表达式:
fileOperate() async{
// 读取文件
var file = await readFile();
// 其他处理
}
元数据
使用元数据给代码添加更多的信息。元数据是以@开始的修饰符,在@后面接着编译时的常量或调用一个常量构造函数。
目前Dart语言提供三个@修饰符:
@deprecated被弃用的。
@override重写。
@proxy代理。
元数据可以修饰library(库)、class(类)、typedef(类型定义)、type paremeter(类型参数)、constructot(构造函数)、factory(工厂函数)、function(函数)、field(作用域)、parameter(参数)、variable declaration(变量声明)。