typedef
//没返回值,则只要参数匹配就行了,如果定义了返回值,则返回值不一样会报错
typedef Fun1(int a, int b);
typedef Fun2(T a, K b);
int add(int a, int b) {
print('a + b');
return a + b;
}
class Demo1 {
Demo1(int f(int a, int b), int x, int y) {
var sum = f(x, y);
print("sum1 = $sum");
}
}
class Demo2 {
Demo2(Fun1 f, int x, int y) {
var sum = f(x, y);
print("sum2 = $sum");
}
}
class Demo3 {
Demo3(Fun2 f, int x, int y) {
var sum = f(x, y);
print("sum3 = $sum");
}
}
goTypedef() {
Demo1 d1 = new Demo1(add, 2, 3);
Demo2 d2 = new Demo2(add, 5, 6);
Demo3 d3 = new Demo3(add, 5, 6);
}
泛型
Dart 的泛型类型是固化的,在运行时有也可以判断具体的类型。
void goGeneric() {
//list
var colors1 = ['red', 'green', 'blue'];
//Map
var colors2 = {
'first': 'red',
'second': 'green',
'third': 'blue'
};
var colors3 = new List();
colors3.addAll(['red', 'green', 'blue']);
print(colors3 is List); //java在运行时不判断泛型
}
控制语句
- if and else
- for loops
- while and do-while loops
- break and continue
- switch and case
- assert
for
//List 和 Set 等实现了 Iterable 接口的类还支持 for-in 形式的遍历
void goFor(){
//for-in 形式
var collection = [0, 1, 2];
for (var x in collection) {
print(x);
}
//forEach形式
List list = ['a','b','c'];
list.forEach((i)=>print(i));
}
while and do-while
void goWhile(){
int a = 1;
while(a < 5){
print('goWhile a = $a');
a++;
if(a == 4){
break;
}
}
int b = 0;
do{
b ++;
print('goWhile b = $b');
}while(b < 0);
}
Switch and case,enum
- 每个非空的 case 语句都必须有一个 break 语句。 另外还可以通过 continue、throw 或者 return 来结束非空 case 语句。
- case都必须是编译时常量,这些常量必须符合以下条件:
- 都是int的实例
- 都是String的实例
- 都是同一个类的实例且该类必须从Object继承了==的实现
- switch使用==比较,class必须没有覆写==操作符
void goSwitch() {
switch ("flutter") {
case "jimmy":
print('hello jimmy');
break;
case "flutter":
print("hello flutter");
break;
}
//switch中使用枚举需要把所有枚举值case一边,或者加default,否则会有警告
Color color = Color.red;
switch (color) {
case Color.red:
break;
case Color.blue:
break;
//case Color.green:
//break;
default:
}
switch (color) {
case Color.red:
print("color.red");
continue goGreen;
case Color.blue:
print("color.blue");
break;
goGreen:
case Color.green:
print("color.green");
break;
default:
}
}
enum Color { red, green, blue }
void goEnum() {
print('Color.red = ${Color.red}');
print('Color.red = ${Color.red.index}');
//values 返回所有枚举值
List colors = Color.values;
assert(colors[2] == Color.blue);
}
Exceptions(异常)
Throw 可以抛出任意对象
void goThrow() {
try {
getName2();
} catch (e,s) {
//函数 catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象,
// 第二个为堆栈信息 (一个 StackTrace 对象)。
print("goThrow catch = $e,$s");
} finally {
print('goThrow finally');
}
}
getName2() {
//你可以使用on 或者 catch 来声明捕获语句,也可以同时使用。
// 使用 on 来指定异常类型,使用 catch 来捕获异常对象。
try {
getName();
} on Exception {
print("getName2:Exception");
} on NullThrownError catch (e) {
print("getName2 on = $e");
//使用 rethrow 关键字可以 把捕获的异常给 重新抛出。
rethrow;
} catch (e) {
// 没指定类型,捕获任何异常类型
print("getName2 catch $e");
}
}
getName() {
if (true) {
throw new NullThrownError();
}
}
构造函数
//java中写法
class Point1 {
num x;
num y;
Point1(num x, num y) {
this.x = x;
this.y = y;
}
}
//dart建议写法
class Point2 {
num x;
num y;
Point2(this.x, this.y);
}
命名构造函数
Dart语言是不支持方法重载的。构造函数的重载也不支持,但是它支持命名构造函数。
Point2.fromJson(Map json) {
x = json['x'];
y = json['y'];
}
重定向构造函数
一个重定向构造函数是没有代码的,在构造函数声明后,使用冒号调用其他构造函数。
Point2.alongXAxis(num x) : this(x, 0);
超类构造函数
class Point3 extends Point2 {
Point3.fromJsonCustom(Map data):super.fromJson(data){
print('in point');
}
}
void goPoint3(){
var point3 = new Point3.fromJsonCustom({'x':5,'y':6});
var px = point3.x;
var py = point3.y;
print('x=$px y=$py');
var point2 = new Point2.alongXAxis(15);
var px2 = point2.x;
var py2 = point2.y;
print('x2=$px2,y2=$py2');
}
Initializer list(初始化列表)
初始化列表非常适合用来设置 final 变量的值。
import 'dart:math';
class Point3 {
final num x;
final num y;
final num distanceFromOrigin;
Point3(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
void goPoint3() {
var p = new Point3(2, 3);
print(p.distanceFromOrigin);
}
工厂构造函数
class A {
String name;
static A _cache;//注意工厂模式无法使用this.所以这儿要静态的
A._newObject(this.name);//需要一个命名构造函数来生产实例
factory A(name1){
if (A._cache==null) {
A._cache =new A._newObject(name1);
}
return A._cache;//没有实例创建实例对象并缓存,缓存中有实例对象,直接使用
}
}
void goFactory(){
A a =new A('HelloWorld');
print(a.name);
A b = new A('helloDart');
print(b.name);
print(a==b);
/*输出:
HelloWorld
HelloWorld
true
*/
}
Getters and setters
class GetAndSet {
num a;
num b;
GetAndSet(this.a,this.b);
set c (num value){//(先)赋值
print('set c');
a = value + b;//随便定义一个方法:重新给a赋值
}
num get c{//(再)取值
print('get c');
return a + b;
}
}
goGetAndSet(){
var i =new GetAndSet(5, 9);
i.c = 4;//给c赋值
var k = i.c;//获取c的值
print('i.a = ${i.a},i.b = ${i.b},k = $k');
}
抽象类
//使用 abstract 修饰符来定义一个抽象类,该类不能被实例化。抽象类在定义接口的时候非常有用,实际上抽象中也包含一些实现。如果你想让你的抽象类被实例化,请定义一个 工厂构造函数 。
abstract class Car {// 这个类是抽象类,因此不能被实例化。
run();// 抽象方法。
space() {}
}
//下面的类不是抽象类,因此它可以被实例化,即使定义了一个抽象方法:
class Bus extends Car {
int width = 4;//设置默认值
Bus(this.width);
@override
run() {
print('Bus 起飞跑');
}
}
接口实现
- 每个类都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。
- 如果你想创建类A来支持类B的api,而不想继承B的实现,则类A应该实现类B的接口。
- 一个类可以通过 implements 关键字来实现一个或者多个接口, 并实现每个接口定义的 API。
// 一个 person ,包含 greet() 的隐式接口。
class Person {
// 在这个接口中,只有库中可见。
final _name;
// 不在接口中,因为这是个构造函数。
Person(this._name);
// 在这个接口中。
String greet(who) => 'Hello, $who. I am $_name.';
}
// Person 接口的一个实现。
class Imposter implements Person {
// 我们不得不定义它,但不用它。
final _name = "";
String greet(who) => 'Hi $who. Do you know who I am?';
}
greetBob(Person person) => person.greet('bob');
main() {
print(greetBob(new Person('kathy')));
print(greetBob(new Imposter()));
}
//这里是具体说明一个类实现多个接口的例子:
class Point implements Comparable, Location {
// ...
}
mixin
特性:
- 传统的接口概念中,并不包含实现部分,而Mixin包含实现。
如何定义一个mixin的类:
- 定义一个类继承 Object
- 该类没有构造函数
- 不能调用 super ,则该类就是一个 mixin
//可以是抽象的,也可以不是
class S {
// a() {
// print("S.a");
// }
// b() {
// print("S.b");
// }
// c() {
// print("S.c ");
// }
}
class A {
a() {
print("A.a");
}
b() {
print("A.b");
}
}
class B {
a() {
print("B.a");
}
b() {
print("B.b");
}
c() {
print("B.c ");
}
}
class T extends B with A,S{
}
// class T = B with A, S;
main() {
T t = new T();
t.a();
t.b();
t.c();
assert(t is S);//mixins的类型就是其超类的子类型,所以都会为ture
}