变量
变量的声明以及赋值:
//如果不初始化,则后续可以赋值任意类型,最终类型是dynamic类型,dynamic类型不会检测成员
var name = "Bozo";
复制代码
在声明变量的时候,也可以选择使用具体的数据类型:
//使用确定类型定义变量,赋值必须是相同类型
String name = "bozo";
int age = 12;
double height = 176.3;
bool onLine = true;
复制代码
没有初始化变量默认值都为
null
,即使变量类型为bool
或者int
Dart中的基本数据类型:num
、double
、int
、String
、List
、Set
、String
、map
、bool
、runes
、Symbol
、Object
、dynamic
Dart中所有数据类型都是对象,都继承自
Object
类,null
也继承自Object
类
const&final
使用const
跟final
定义的变量都只能赋值一次,并且在声明的时候必须进行初始化。
使用const
定义的集合都是只读的,特性会传递到子元素,在内存中会复用相同内容对象,而final
则不会作用于子元素,在内存中也不会复用相同对象
//不可以通过 list[0] = 5; 来修改集合中元素的值, 如果换做final来定义则可以修改
const list = [1,2,3,4];
const list2 = [1,2,3,4];
//此时输出的结果为 true, 如果集合是用final定义的则输出结果为 false
print(identical(list, list2));
复制代码
实例变量可以为
final
但是不能是const
方法
方法可以赋值给变量,也可以当作其他方法的参数,以下为定义方法的示例:
bool isEmpty(String str){
return str == null || str == "";
}
//可以忽略类型定义
isEmpty(str){
return str == null || str == "";
}
//如果是只有一个表达式的方法,则可以使用缩写语法来定义
isEmpty(str) => str == null || str == "";
复制代码
在Dart中方法还可以设置可选参数,以及设置默认值
void main() {
printInfo("Bozo", 13, true);
//可选位置参数
// printInfo("Bozo", false);
//可选命名参数
// printInfo(name: "Bozo", showAge: false);
//指定默认值
// printInfo(name: "Bozo", showAge: true);
}
printInfo(name, age, showAge) {
if (showAge) {
print("name:$name,age:$age");
} else {
print("name:$name");
}
}
//可选位置参数
printInfo(name, showAge, [age]) {
......
}
//可选命名参数
printInfo({name, age, showAge}) {
......
}
//指定默认值
printInfo({name, age = 12, showAge}) {
......
}
复制代码
所有函数都有一个返回值,如果没有指定返回值,则默认把
return null;
作为函数得最后一个语句执行
操作符
操作符重载
以下操作符可以被重载
例如重写+
跟-
操作符
class Vector{
final int x;
final int y;
Vector(this.x, this.y);
Vector operator +(Vector v){
return Vector(x + v.x, y + v.y);
}
Vector operator -(Vector v){
return Vector(x - v.x, y - v.y);
}
}
void main(){
Vector v1 = Vector(4, 3);
Vector v2 = Vector(2, 1);
Vector v3 = v1 - v2;
Vector v4 = v1 + v3;
//print: v3:x=2,y:2
print("v3:x=${v3.x.toString()},y:${v3.y.toString()}");
//print: v4:x=6,y:5
print("v4:x=${v4.x.toString()},y:${v4.y.toString()}");
}
复制代码
如果覆写的操作符是
==
,则还应覆写对象的hashCode
getter 函数
类型判定操作符
as
、is
、is!
操作符是在运行时判定对象类型的操作符
操作符 | 解释 |
---|---|
as | 类型转换 |
is | 如果对象是指定的类型返回true |
is! | 如果对象是指定的类型返回false |
级联操作符
级联操作符 (..
) 可以在同一个对象上 连续调用多个函数以及访问成员变量,使用级联操作符可以避免创建 临时变量
void main() {
Person()
..name = 'bozo'
..age = 12
..contact = (new Contact()
..phoneNumber = '126854315'
..email = 'bozo@gmail.com')
..showInfo();
}
class Person {
String name;
int age;
Contact contact;
showInfo() {
print("Name:${this.name},Age:${this.age},PhoneNumber:${this.contact.phoneNumber},Email:${this.contact.email}");
}
}
class Contact {
String phoneNumber;
String email;
}
复制代码
异常
抛出异常
throw new FormatException('Expected at least 1 section!');
//还可以抛出任意对象
throw 'Out of llamas!'
复制代码
捕获异常
try {
throwExceptionsFuc();
} on FormatException {
...
} on Exception catch (e) {
...
} catch (e) {
...
} finally {
...
}
}
复制代码
可以使用
on
或者catch
来声明捕获语句,也可以同时使用。使用on
来指定异常类型,使用catch
来捕获异常对象,函数catch
可以有一个或两个参数,第一个参数为抛出的异常对象,第二个为堆栈信息
还可以使用rethrow
关键字来把捕获的异常重新抛出
try{
testFuc();
} catch (e) {
...
//重新抛出异常
rethrow;
}
复制代码
类
Dart中每个对象都是一个类的实例,所有类都继承于Object
。
构造函数
在Dart中可以使用this
关键字来简化构造函数的实现:
class Person{
String name;
int age;
//原始写法
Person(String name, int age){
this.name = name;
this.age = age;
}
//使用this关键字简化写法
Person(this.name, this.age);
}
复制代码
如果没有定义构造函数,跟Java中一样会有一个默认的无参构造
使用命名构造函数
可以为一个类实现多个构造函数,如果要在一个构造函数中调用其他构造函数则使用重定向构造函数
。
void main() {
Person person1 = new Person("Bozo", 17);
Map map = new Map();
map['name'] = "bozo";
map['age'] = 18;
Person person2 = new Person.fromMap(map);
}
class Person {
String name;
int age;
Person(this.name, this.age);
//命名构造函数
Person.fromMap(Map map) {
this.name = map['name'];
this.age = map['age'];
}
//重定向构造函数
Person.byName(name) : this(name, 0);
}
复制代码
如果要类提供一个状态不变的对象,则可以把对象定义为编译时常量。需要定义一个const
构造函数,并且声明所有的变量为final
。使用常量构造函创建的对象具有复用性,前提是对象的成员变量值相同。
class Car {
final String color;
const Car(this.color);
static final Car car = const Car("red");
}
void main(){
Car car1 = const Car("red");
Car car2 = const Car("black");
//断言执行通过,car1跟car为同一个对象
assert(identical(car1, Car.car));
//断言执行失败
assert(identical(car2, Car.car));
}
复制代码
如果一个构造函数不是总是返回一个新的对象,则可以使用factory
关键字来创建工厂方法构造函数
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to the _ in front
// of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) {
print(msg);
}
}
}
void main(){
var logger = new Logger('UI');
logger.log('Button clicked');
}
复制代码
工厂方法无法访问
this
extends 跟 implements
-
extends
:继承其他类的属性以及方法,在dart中可以使用with
关键字来实现多继承class A extends B with C,D{ ... } 复制代码
-
implements
:一个类可以通过implements
关键字来实现一个或者多个接口, 并实现每个接口定义的 API
枚举
使用 enum
关键字来定义枚举类型,枚举中每个值都有一个index
的属性(从0开始)。枚举的values
常量可以返回所有的枚举值
enum Color{
RED,
GREEN,
BLUE
}
void main(){
List<Color> colors = Color.values;
assert(colors[2] == Color.BLUE);
}
复制代码
泛型
在Dart中使用泛型的方式与Java类似:
abstract class Cache<T>{
T getByKey(String key);
void cacheByKey(String key, T value);
}
复制代码
限制泛型的具体类型:
class SomeClass<T extends SomeBaseClases>{
...
}
复制代码
泛型函数:
T findByIndex<T>(List<T> data, int index) {
return data == null ? data[index] : null;
}
复制代码
库
使用 import
来导入库
//内置库使用 dart:scheme
import 'dart:io';
//其他库使用文件系统路径或者 package:scheme
import 'package:libs/utils.dart';
复制代码
如果导入的两个库具有冲突的标识符,则可以使用库的前缀来区分,例如lib1跟lib2中都存在名为SomeClass的类:
import 'package:libs/lib1.dart';
import 'package:libs/lib2.dart' as lib2;
...
SomeClass class1 = new SomeClass();
lib2.SomeClass class2 = new lib2.SomeClass();
复制代码
如果只想导入库的一部分内容可以使用 show
跟 hide
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
复制代码
如果要让一个库在使用的时候才加载则可以使用延时加载库。如:
//使用 deferred as 导入
import 'package:deferred/hello.dart' deferred as hello;
//当需要使用的时候,使用库标识符调用loadLibrary()函数来加载库
hello.loadLibrary();
hello.sayHello();
复制代码
- 一个库可以调用
loadLibrary()
函数,但该库只会载入一次- 延迟加载库的常量在导入的时候是不可用的。 只有当库加载完毕的时候,库中常量才可以使用。
- 在导入文件的时候无法使用延迟库中的类型。 如果你需要使用类型,则考虑把接口类型移动到另外一个库中, 让两个库都分别导入这个接口库。
- Dart 隐含的把
loadLibrary()
函数导入到使用deferred as *的命名空间*
中。loadLibrary()
方法返回一个 Future。
异步
异步方法的声明是添加 async
关键字,如:
...
checkVersion() async{
...
}
复制代码
使用await来等待异步方法返回:
...
//要使用 await,其方法必须带有 async 关键字
checkVersion() async{
var version = await getVersionInfo();
...
}
复制代码