--- title: dart初见(2) date: 2019-10-06 21:08:37 tags: - dart categories: - flutter --- ### 函数相关 dart当中函数也是一个对象,具备共同的抽象类`Function` 因为是抽象类,所以不能直接用其执行new创建对象 #### 可选参数 dart在定义函数的时候可以在形参表的末尾添加可选参数 有命名参数和匿名参数两种形式 ```dart void main() { func1('Sookie', c: true, b: 10); func2('Sookie', 20, false); } // 命名可选参数 void func1(String a, {int b, bool c}) { print('a=${a},b=${b},c=${c}'); } // 匿名可选参数 void func2(String a, [int b = 100 ,bool c]) { // 可以给可选参数指定默认值 print('a=${a},b=${b},c=${c}'); } ``` 命名的可选参数因为传参时指定形参名称,所以就不会强制顺序的匹配了 可选参数的声明必须在形参表的末尾 #### 匿名函数和箭头函数 **匿名函数** ``` (参数1, 参数2 ...) { 函数体 } ``` 匿名函数不能声明返回值类型,或者说它的返回值是任意类型的,相当于是`dynamic` > dynamic并不算一种类型,只是作为一个关键字表示动态类型 就像var也是关键字,但是会执行类型推导 **箭头函数** ``` (参数1, 参数2 ...) => 返回值 ``` 箭头函数只能有一个表达式作为返回值,而不能有其他语句 函数对象都可以使用变量进行接收 #### 级联调用 dart当中使用`..`来实现级联调用 ```dart List list1 = [10,15,20]; list1..add(19)..remove(10); // 相当于 List list2 = [10,15,20]; list2.add(19); list2.remove(10); ``` ### 面向对象 使用`class`关键字来声明一个类,创建对象时`new`关键字可以省略 dart中不支持函数重载 可以使用`.`来访问对象的成员 当然如果变量是null会报空指针的错误 可以判断是否为null 也可以使用`?.`操作符,相当于自带判断是否为null,如果是null就不执行调用 类如果实现了`call`函数,那么它的实例就可以直接当做函数来执行调用 ```dart void main() { Demo demo = new Demo(); demo('hello'); } class Demo{ void call(String msg) { print(msg); } } ``` #### 计算属性 对于不是固定值,而是需要使用一些逻辑获得计算结果的情况 我们可以将其定义为类当中的一个函数,也可以使用计算属性 计算属性分为`get`和`set`两种 ```dart void main() { Rectangle rect = new Rectangle(); rect.width = 10.9; rect.height = 20.3; print(rect.area); // 221.27 rect.area = 100; print(rect.width); // 5.0 } class Rectangle { num width, height; num get area { return width * height; } void set area(num value) { this.height = 20; this.width = value / 20; } } ``` > 它本身当然是个函数,也可以使用箭头函数的写法 #### 构造函数 定义一个类时,如果不写构造函数,会默认提供一个无参的构造函数 支持匿名构造函数与命名构造函数两种 构造函数也不能被重载,如果要实现一个类有多个构造函数,就必须使用命名构造函数 ```dart class Person { String name; int age; // 匿名构造函数 Person(String name, int age) { this.name = name; this.age = age; } // 也可以写作 // Person(this.name, this.age); // 命名构造函数 Person.withName(String name) { this.name = name; } } ``` 命名构造函数调用时写作 **new Person.withName('sookie')** 对于`final`修饰的类属性,想要在构造函数进行初始化,只能使用这种语法糖的形式来写 ```dart class Person { final String name; int age; Person(this.name, this.age); Person.withName(this.name); // 下面的方式是报错的 // Person(String name, int age) { // this.name = name; // this.age = age; // } // 这种方式当然也报错 // Person.withName(String name) { // this.name = name; // } } ``` ##### 常量对象 ```dart void main() { const Person p = const Person('Sookie', 18); print(p.name); } class Person { final String name; final int age; const Person(this.name, this.age); } ``` ##### 工厂构造方法 dart自带了工厂设计模式的实现,工厂构造方法需要返回该类的实例对象 ```dart class Logger { String name; static final Map _cache = new Map(); factory Logger(String name) { if(!_cache.containsKey(name)) { _cache[name] = new Logger(name); } return _cache[name]; } } ``` #### 类型转换 使用`as`进行强制类型转换 使用`is`和`is!`来判断是否属于某种类型 ```dart dynamic a = 'abc'; if(a is String) { print((a as String).toUpperCase()); } ``` 如果不执行强制类型转换,就不能直接调用String上的方法,因为此时a还是动态类型 #### 继承 dart当中的继承与java基本类似 + 使用`extends`关键字实现继承,只能单继承,具备多态特性 + 子类会继承父类可见的成员,不会继承构造方法 + 子类可以重写父类的方法(重写的方法上可以添加`@override`注解) + 所有类都有公共的基类`Object` ##### 构造函数 子类的构造函数会默认隐式调用父类无名无参的构造函数 如果父类当中没有,则需要使用super显式调用 ```dart class Demo1{ String name; Demo1(String name) { print('Demo1:${name}'); } Demo1.withName(String name) { this.name = name; } } class Demo2 extends Demo1 { // 显式调用父类的匿名构造函数 Demo2(String name):super(name) { print('Demo2:${name}'); } // 显式调用父类的命名构造函数 Demo2.withName(String name):super.withName(name) { this.name = name; } } ``` #### 抽象类与接口 抽象类使用`abstract`修饰,跟Java基本一样,可以定义抽象方法或者有具体实现的方法(抽象方法并不需要再加abstract修饰) 但是并不存在interface关键字 一个类本身就可以当做接口来使用 ```dart class Demo{ String name; void test(String msg) { print(msg); } } // 如果作为接口使用,就必须重写所有的属性与方法 class Demo1 implements Demo { @override String name; @override void test(String msg) { // TODO: implement test } } ``` 当然这是非常冗余的,至少属性没什么好重写的 所以实际开发当中通常把抽象类当做以往意义上的接口来使用 #### Mixins 使用extends只能实现单继承,Mixins就是多继承的一种实现方式 使一个类同时拥有多个类的成员 ```dart class A { void a() { print('A.a'); } } class B { void b() { print('B.b'); } } class C with A,B { //这个类中同时具备A,B两个类的成员 } // 如果类中不需要添加其他成员,也可以使用如下简写方式 class D = A with B; ``` 如果A和B当中存在同名方法,那么就是根据**with之后的声明顺序** A在前B在后,所以C中实际具备的是B当中的该方法 需要注意的是with后面跟的类 1. **不能**有显式声明的构造函数 2. **只能**直接继承自Object(可以省略 extends Object) 3. 可以使用implements实现接口 ### 模块化 + 可见性以`library`(库)为单位,差不多可以理解为JavaScript当中的模块 + 每一个dart文件就是一个库 + 以`_`开头声明的类或者函数是在当前库当中私有的,即使其他库引入了该库,也无法在其他库中使用 + 使用`import`来引入一个库文件 + dart的sdk有自带的一套类库,`dart.core`是默认被引入的