Dart常用核心知识
Posted 滴水微澜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dart常用核心知识相关的知识,希望对你有一定的参考价值。
Dart简述
Dart 是一个为全平台构建快速应用的客户端优化的编程语言,免费且开源。
Dart是面向对象的、类定义的、单继承的语言。它的语法涵盖了多种语言的语法特性,如C,JavaScirpt, Java, Swift等语言,可以转译为JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型(reified generics)、可选类型(optional typing)和sound type system。
下面整理了Dart这门语言的核心知识点。
1.变量声明
2.字符串
3.集合
4.函数
5.赋值运算符
6.面向对象
7.枚举
8.库的使用
1.变量的声明
dart变量的声明有两种,常量和变量。使用常量可以保证在定义一个变量后,如果后面赋值了不同的类型的值,会在编译期报错,提高安全性。
常量
1.const编译时常量,这种常量值要在编译前确定。
2.final运行时常量,这种常量值可以在运行时再确定。
变量
1.显示声明,如使用String name定义变量。
2.var类型推导,有编译器自动推导。虽然使用的var定义变量,此时的变量依然是确定的类型。
void main(List<String> args) print("Hello Dart"); // 显示声明 String name = \'jack\'; // 类型推断:类型推断的,也是有类型的。不同类型之间不能赋值。 // 类型推断变量 var age = 20; age = 30; // age = 30.3; // 编译期常量 const school = \'北京大学\'; // 运行时常量 final local = DateTime.now(); const p1 = const Person(\'Tom\'); const p2 = const Person(\'Tom\'); const p3 = const Person(\'LiLei\'); print(identical(p1, p2)); print(identical(p1, p3)); class Person final String name; // 构造函数传参直接赋值到name属性上。 const Person(this.name);
2.字符串
定义字符串有三种方式:单引号,双引号,三引号。
字符串的拼接规则和shell语法一样,$变量名后面没有其他符号时使用$变量名,后面紧跟其他符号产生歧义时,使用$变量名
void main(List<String> args) // 定义字符串三种方式:单引号,双引号,三引号 var str1 = \'abc\'; var str2 = "def"; var str3 = """ ghi jkl mn """; print(str3); // 字符串拼接: 拼接规则和shell很相似 var name = \'jack\'; var age = 30; var height = 190.3; var msg1 = "name is $name, age is $age, height is $height, height Type is $height.runtimeType"; print(msg1);
3.集合
dart中有三种集合, dart在集合中广泛使用泛型来表示集合中存放的是什么类型。
1.列表List: 使用[‘ABC’]进行定义
2.集合Set: 使用\'abc\', 可以对列表List去重
3.哈希Map: 使用\'name\': value,使用的键值对进行定义
void main(List<String> args) // dart中没有关键字定义接口,默认情况下,所有的class都是隐式接口 // dart在集合中广泛使用泛型来表示集合中存放的是什么类型。 // 1.列表List var names = [\'abc\', \'cba\', \'nba\', \'cba\', \'abc\']; names.add(\'hhh\'); print(names); print(names.runtimeType); // 2.集合Set var movies = \'星际穿越\', \'大话西游\', \'盗梦空间\'; names = Set<String>.from(names).toList(); print(names); print(movies); // 3.映射Map // 映射的Key应该是可以求出hash值的。 var info = \'name\': \'jack\', \'age\': 30 ; Map; print(info); print(info.runtimeType);
4.函数
函数的定义
dart 函数的形式和 C 语言相似,形式为:返回值 函数名(参数) 函数体
其中返回值部分可以省略有编译器自动推导,但是推荐写上,方便开发人员理解。
dart 中没有函数的重载。
函数的可选参数
可选参数类型有:位置可选参数 、命名可选参数两种。
位置可选参数形式为:[int age, double height],实参和形参在进行匹配时,是根据位置匹配的。
命名可选参数:int age, double height,实参和形参在进行匹配时,需要根据名称进行设置。
可选参数可以有默认值,必传参数不能设置默认值。
函数是一等公民
一等公民是很灵活的,可以作为参数和返回值。
OC 中使用 Block 实现这一特性。
匿名函数
因为 dart 中函数为一等公民,所以在函数作为参数进行传参时,可以将函数写成匿名函数的形式。
参数中的匿名函数有两种形式:
匿名函数体是单条语句时,可以用是箭头函数表示
testFunc(() => print(\'箭头匿名函数,只能有一条语句\') );
当匿名函数体中的语句多行时,使用下面的形式
// 多条语句 testFunc(() print(\'匿名函数被调用\'); );
匿名传参,参数需要定义为完整的函数签名,也可以使用下面类型定义的方式。
typedef Calculate = int Function(int num1, int num2); void testFoo2(Calculate cal) cal(10, 10);
void main(List<String> args) print(sayHi(10, 20)); // 顺序可选参数,传参的顺序必须和定义顺序相同 sayHello1(\'jack\', 30); // 命名可选参数,传参需要带定义的名称 sayHello2(\'jack\', age: 30); testFunc(foo); // 1.函数的定义 // 返回值类型int 可以省略,但是推荐保留 int sayHi(int height, int age) return age + height; // 2.函数的可选参数 /* dart中没有函数的重载 可选参数:位置可选参数 - 命名可选参数 可选参数可以默认值,必传参数不需要默认值 */ // 位置可选参数 void sayHello1(String name, [int age, double height]) // 命名可选参数 void sayHello2(String name, int age, double height) // 命名可选参数带默认值 void sayHello3(String name, int age, double height = 12) // 3.函数是一等公民 /* 一等公民是很灵活的,可以作为参数和返回值。 OC中使用Block实现这一特性 */ void testFunc(Function foo) foo(); void foo() print(\'foo 函数被调用\'); // 4.匿名函数 void testFunc2() // 多条语句 testFunc(() print(\'匿名函数被调用\'); ); // 单条语句 testFunc(() => print(\'箭头匿名函数,只能有一条语句\') ); // 匿名函数传参 /* 匿名传参,参数需要定义为完整的函数签名:void testFoo(int foo(int num1, int num2)) */ testFoo((num1, num2) => num1 + num2); testFoo2((num1, num2) => num1 + num2); // 匿名返回值 var foo3 = testFoo3(); foo3(3, 3); void testFoo(int foo(int num1, int num2)) print(foo(10, 20)); typedef Calculate = int Function(int num1, int num2); void testFoo2(Calculate cal) cal(10, 10); Calculate testFoo3() return (int num1, int num2) => num1 * num2;
5.赋值运算符
Dart中比较特别的运算符有: ??=, ??, 级联运算符
??=
如果运算符 ??=前面的变量为null就执行后面的=赋值操作,如果pro有值就不执行后面的操作。
特点:可能有赋值操作。
使用场景如:pro ??= name;
??
??是?:三目运算符号的简写, 如果前面的变量有值则取前面的值,如果前面的值为空就取后面的值。
特点:一定有赋值操作。
使用场景如:school = pro ?? \'没人上学\';
级联运算符..
级联运算符可以连续对实例对象调用方法或属性
void main(List<String> args) // ??=: 如果前面的pro为null就执行后面的=赋值操作,如果pro有值就不执行后面的操作。 // 可能有赋值操作 var name = \'jim\'; var pro = null; pro ??= name; print(pro); // ??: 是?:三目运算符号的简写, 如果前面的变量有值则取前面的值,如果前面的值为空就取后面的值。 // 一定有赋值操作 var school = \'小学\'; school = pro ?? \'没人上学\'; print(school); // 级联运算符:可以连续调用..方法 var p = Person() ..name = \'jim\' ..eat() ..run(); p.eat(); class Person var name; void eat() void run()
6.面向对象
1.类的基本定义
dart中的类默认继承在Object类,创建的实例对象可以调用Object中的方法。
如果不自定义结构函数,系统会给类自动创建一个空参数的构造函数。
// 类默认是继承自Object的,应用创建的对象是可以使用Object中的方法的。 class Person String name; int age;
2.类的构造函数
dart中类的构造函数有三种:
a.用户没有自定义构造函数时,系统会默认实现一个空参数的构造函数
b.普通构造函数,通过便捷赋值,直接初始化属性值
Student(this.name, this.age);
c.命名构造函数,因为Dart中不支持函数重载,所以出现了命名构造函数来作为构造函数
Student.withNameAgeHeight(this.name, this.age, this.height); Student.withMap(Map<String, dynamic> map) this.name = map[\'name\']; this.age = map[\'age\']; this.height = map[\'height\']; ;
dynamic、var、Object的区别?
var是类型推断。
dynamic是类型声明,相当于Swift中的Any,它是一个具体类型的声明,如String。
Object可以父类指向子类对象。
dynamic是运行时报错, Object是编译时报错。
3.类的初始化列表
dart的构造函数的结构体执行时,是在构造函数执行后,所以对于final属性,它必须在构造函数执行时进行执行。所以此时的执行时间需要在结构体执行,故:它的执行时间是在():后面的初始化列表里执行。
初始化列表:里面执行不仅可以包含编辑期静态返回值,还可以包含动态调用返回值。如:Color.blue
可选命名表达式: 只能有编译器静态赋值表达式,如:int age = temp ?? 20
// 3.类的初始化列表 class Teacher final String name; final int age; // Teacher(this.name, int age = 10, String color): this.color = color ?? \'\' // Teacher():this.name = \'jc\', this.age = 10
4.构造函数重定向
当一个类中定义多个构造函数时,可以在普通构造函数的初始化列表中调用其他命名构造函数。
class Doctor int age; String name; // 构造函数重定向 Doctor(String name): this._internal(name, 10); // 命名构造函数 Doctor._internal(String name, int age);
5.常量构造函数
使用常量构造函数创建的常量对象,如果对象的属性值一样时,返回的实例对象内存地址是一样的,返回的是同一个对象。
// 5.常量构造函数,相同的属性只有一个内存对象。 class Apple final String name; final int age; const Apple(this.name, this.age);
6.工厂构造函数
工厂构造函数最大的特点是可以手动返回对象。
普通构造函数与工厂构造函数的区别:
普通构造函数不需要写return 会自动返回实例对象。
工厂构造函数需要写return 手动返回实例对象。
// 6.工厂构造函数:最大的特点可以手动返回一个对象。 class Orange String name; String color; static final Map<String, Orange> _nameCache = ; static final Map<String, Orange> _colorCache = ; factory Orange.withName(String name) if (_nameCache.containsKey(name)) return _nameCache[name]; else final p = Orange(name, \'red\'); _nameCache[name] = p; return p; Orange(this.name, this.color);
7.Setter, Getter
在Dart中没有private public等修饰符,当对属性_开头时,表示这个属性是私有属性,只能在当前文件模块内访问。
// 7.Setter, Getter进行属性监听 // 使用方式是: var e = Elephone(); e.setName(\'jim\'); e.getName class Elephone String name; // 在Dart中没有private public等修饰符,当对属性_开头时,表示这个属性是私有属性,只能在当前文件模块内访问。 String _age; // setter set setName(String name) this.name = name; // getter String get getName return name;
8.继承
子类继承父类时,父类有构造函数时,需要在子类的参数列表中进行调用,进行初始化。
// 8.继承:父类的构造函数要在子类的初始化列表中进行调用。 class Animal String name; Animal(this.name); void eat() print(\'eatting\'); class Dog extends Animal int age; // 父类有构造函数时,需要在参数列表中进行调用,初始化。 Dog(this.age, String name): super(name);
9.抽象类
抽象类在使用时有以下特点:
a.子类继承抽象父类,父类的接口方法必须实现,它们都是必选项。因为dart中没有option可选项。
b.抽象类不能被实例化。
c.系统调用抽象类Map进行实例化的过程分析
Map是一个抽象类,而可以调用Map()产生实例对象的原因是因为调用的Map()是Map抽象类的工厂方法 external factory Map();
external关键字 是一个方法存在的声明,表示此方法已经存在,但不在这里实现。这样实现和声明分离
的好处是,可以在实现的地方使用runtimeType集中处理不同平台逻辑,而通过方法接口声明在不同的平台调用。
在方法具体实现的地方使用@patch修饰。
// 9.抽象类 abstract class Shape int getArea(); String getInfo() return \'形状\'; void testMap() final m = Map(); print(m.runtimeType); class Rectangle extends Shape @override int getArea() return 20;
10.dart隐式接口
dart中定义的class同时也可以当接口使用,可以说class定义的即是类,也是接口。当它做为类使用时,里面定义的方法不必须让子类实现。当它做接口时,里面定义的方法都需要被重新实现。
dart是单继承语言。
// 10.dart隐式接口:dart中定义的class同时也可以当接口使用。 class Runner void run() print(\'running\'); class Fly void fly() print(\'fly\'); class SuperMan extends Animal implements Runner, Fly SuperMan(String name):super(name); // 1.接口实现 @override void run() // TODO: implement run @override void fly() // TODO: implement fly // 2.方法重写 @override void eat() // TODO: implement eat super.eat();
11.混入mixin
dart是单继承语言。
当出现需求想要同时拥有多个类中的方法和属性时,可以通过 混入mixin来间接实现多继承。
可以同时引入多个mixin类中的方法。
dart是单继承, 如果要想同时引入多个mixin类中的方法,则可以定义多个mixin类来引入。
定义用mixin,使用用with。
// 11.混入mixin mixin Play void play() print(\'play\'); mixin Jump void jump() print(\'jump\'); class Robbit extends Animal with Play, Jump Robbit(String name):super(name); @override void eat() // TODO: implement eat super.eat();
12.static 类属性,类方法
可以通过static静态声明来定义类属性和类方法/*
12.static 类属性,类方法 */ class SuperWoman // 成员变量,成员方法 var name; void fly() // 静态/类变量,静态/类方法 static var flyYear; static void run()
void main(List<String> args) // 虽然dart支持函数式开发,但是大部分使用的是面向对象开发。 var p0 = Person(\'jim\', 22); print(p0.toString()); var s0 = Student.withMap( \'name\': \'jack\', \'age\': 18, \'height\': 33.3 ); print(s0); // 1.类的基本定义 // 类默认是继承自Object的,应用创建的对象是可以使用Object中的方法的。 class Person String name; int age; // Person(String name, int age) // this.name = name; // this.age = age; // // 语法糖 Person(this.name, this.age); // 2.类的构造函数 class Student String name; int age; double height; // a.普通的构造方法 Student(this.name, this.age); // b.命名构造函数:因为Dart中不支持函数重载,所以出现了命名构造函数来作为构造函数 Student.withNameAgeHeight(this.name, this.age, this.height); /* dynamic和Object的区别 dynamic是类型声明,var是类型推断,它是一个具体类型的声明,如String。 dynamic是运行时报错 Object是编译时报错 Object可以父类指向子类对象。 Object obj = \'hello\'; print(obj.toString(1)); */ Student.withMap(Map<String, dynamic> map) this.name = map[\'name\']; this.age = map[\'age\']; this.height = map[\'height\']; // c.重新类的描述方法 @override String toString() // TODO: implement toString return "$age, $name, $height"; // 3.类的初始化列表 class Teacher final String name; final int age; /* 构造函数的结构体执行时,是在构造函数执行后,所以对于final属性,它必须在构造函数执行时进行执行 所以此时的执行时间就是在结构体执行时,故:它的执行是在():后面的初始化列表里执行。 初始化列表:里面执行不仅包含编辑期静态返回值,还可以包含动态调用返回值。如:Color.blue 可选命名表达式: 只能有赋值表达式,如:int age = temp ?? 20 */ // Teacher(this.name, int age = 10, String color): this.color = color ?? \'\' // Teacher():this.name = \'jc\', this.age = 10 // 4.构造函数重定向 class Doctor int age; String name; // 构造函数重定向 Doctor(String name): this._internal(name, 10); // 命名构造函数 Doctor._internal(String name, int age); // 5.常量构造函数,相同的属性只有一个内存对象。 class Apple final String name; final int age; const Apple(this.name, this.age); // 6.工厂构造函数:最大的特点可以手动返回一个对象。 /* 普通构造函数不需要写return 会自动返回实例对象。 工厂构造函数需要写return 手动返回实例对象。 static:全局静态方法,类方法。 */ class Orange String name; String color; static final Map<String, Orange> _nameCache = ; static final Map<String, Orange> _colorCache = ; factory Orange.withName(String name) if (_nameCache.containsKey(name)) return _nameCache[name]; else final p = Orange(name, \'red\'); _nameCache[name] = p; return p; Orange(this.name, this.color); // 7.Setter, Getter进行属性监听 // 使用方式是: var e = Elephone(); e.setName(\'jim\'); e.getName class Elephone String name; // 在Dart中没有private public等修饰符,当对属性_开头时,表示这个属性是私有属性,只能在当前文件模块内访问。 String _age; // setter set setName(String name) this.name = name; // getter String get getName return name; // 8.继承:父类的构造函数要在子类的初始化列表中进行调用。 class Animal String name; Animal(this.name); void eat() print(\'eatting\'); class Dog extends Animal int age; // 父类有构造函数时,需要在参数列表中进行调用,初始化。 Dog(this.age, String name): super(name); // 9.抽象类 // a.子类继承抽象父类,父类的接口方法必须实现,没有option可选项。 // b.抽象类不能实例化 /* c.系统抽象类Map实例化分析 Map是一个抽象类,而可以调用Map()产生实例对象的原因是因为 调用的Map()是Map抽象类的工厂方法external factory Map(); external 是一个方法存在声明,表示此方法已经存在,但不在这里实现。这样实现和声明分离 的好处是,可以在实现的地方使用runtimeType集中处理不同平台逻辑,而通过方法接口声明在不同的平台 调用。 实现的地方使用@patch修饰。 */ abstract class Shape int getArea(); String getInfo() return \'形状\'; void testMap() final m = Map(); print(m.runtimeType); class Rectangle extends Shape @override int getArea() return 20; // 10.dart隐式接口:dart中定义的class同时也可以当接口使用。 /* dart中没有interface/ protocal这样专门定义接口的关键字 dart中定义的class 同时也具有接口的功能,把class当接口使用时,class中定义的方法必须要全部实现。 dart是单继承 */ class Runner void run() print(\'running\'); class Fly void fly() print(\'fly\'); class SuperMan extends Animal implements Runner, Fly SuperMan(String name):super(name); // 1.接口实现 @override void run() // TODO: implement run @override void fly() // TODO: implement fly // 2.方法重写 @override void eat() // TODO: implement eat super.eat(); // 11.混入mixin /* 混入mixin间接实现多继承,可以同时引入多个mixin类中的方法 dart是单继承, 如果要想同时引入多个mixin类中的方法,则可以定义多个mixin类来引入 定义用mixin 使用用with */ mixin Play void play() print(\'play\'); mixin Jump void jump() print(\'jump\'); class Robbit extends Animal with Play, Jump Robbit(String name):super(name); @override void eat() // TODO: implement eat super.eat(); /* 12.static 类属性,类方法 */ class SuperWoman // 成员变量,成员方法 var name; void fly() // 静态/类变量,静态/类方法 static var flyYear; static void run()
7.枚举
Dart相比JavaScript增加了枚举类型。
void main(List<String> args) var color = Colors.red; switch (color) case Colors.blue: print(\'蓝色\'); break; case Colors.red: print(\'红色\'); break; case Colors.yellow: print(\'黄色\'); break; default: ; print(Colors.values); enum Colors red, blue, yellow
8.库的使用
dart中,一个文件就是一个模块或一个库。
dart中的库有三种:系统库,自定义库,第三方库。
系统库:dart中的Core核心库无需导入,默认导入。如使用的Map
如果使用其他专门功能,就导入专门的库,如:
import \'dart:async\'; import \'dart:io\'; import \'dart:库的名称\';
import \'08_dart_自定义库_utils/math_utils.dart\' 如果自定义库和当前模块或系统库方法名重复,可以是as重命名来区分 import \'08_dart_自定义库_utils/math_utils.dart\' as MathUtils;
import \'package:http/http.dart\' as http;
1.as关键字可以给库起别名
2.默认情况下,导入一个库时会导入库中的所有内容,此时可以使用修饰词声明部分导入
show: 声明要导入的部分
hide: 声明要隐藏的部分
import \'08_dart_自定义库_utils/math_utils.dart\' as MathUtils; import \'08_dart_自定义库_utils/math_utils.dart\' show sum; import \'08_dart_自定义库_utils/math_utils.dart\' hide sub ;
export \'io_utils.dart\'; export \'math_utils.dart\';
4.库文件中的私有方法是_开头的方法。
5.flutter项目第三方库管理文件pubspec.yaml, 然后执行pub get进行更新。
name: zhoufei description: a dart lib dependencies: http: ^0.12.0
import \'dart:math\'; import \'dart:convert\' as convert; import \'08_dart_自定义库_utils/math_utils.dart\' as MathUtils; // import \'08_dart_自定义库_utils/math_utils.dart\' show sum; // import \'08_dart_自定义库_utils/math_utils.dart\' hide sub ; import \'package:http/http.dart\' as http; void main(List<String> args) async final num1 = 10; final num2 = 20; print(min(num1, num2)); MathUtils.sub(num1, num2); var url = Uri.https(\'www.googleapis.com\', \'/books/v1/volumes\', \'q\': \'http\'); // Await the http get response, then decode the json-formatted response. var response = await http.get(url); if (response.statusCode == 200) var jsonResponse = convert.jsonDecode(response.body) as Map<String, dynamic>; var itemCount = jsonResponse[\'totalItems\']; print(\'Number of books about http: $itemCount.\'); else print(\'Request failed with status: $response.statusCode.\'); /* dart中,一个文件就是一个模块或一个库 注意: 1.as关键字可以给库起别名 2.默认情况下,导入一个库时会导入库中的所有内容,此时可以使用修饰词声明部分导入 show: 声明要导入的部分 hide: 声明要隐藏的部分 import \'08_dart_自定义库_utils/math_utils.dart\' as MathUtils; import \'08_dart_自定义库_utils/math_utils.dart\' show sum; import \'08_dart_自定义库_utils/math_utils.dart\' hide sub ; 3.export统一导出一类库文件,当一个目下有多个工具库时,可以统一放到一个文件中,集中导入防止每个都导入一次 export \'io_utils.dart\'; export \'math_utils.dart\'; 4.库文件中的私有方法是_开头的方法。 5.flutter项目第三方库管理文件pubspec.yaml, 然后执行pub get进行更新。 name: zhoufei description: a dart lib dependencies: http: ^0.12.0 系统库 dart中的Core核心库无需导入,默认导入。如使用的Map 如果使用其他专门功能,就导入专门的库,如: import \'dart:async\'; import \'dart:io\'; import \'dart:库的名称\'; 自定义库 导入方式 import \'08_dart_自定义库_utils/math_utils.dart\' 如果自定义库和当前模块或系统库方法名重复,可以是as重命名来区分 import \'08_dart_自定义库_utils/math_utils.dart\' as MathUtils; 第三方库 导入方式 import \'package:http/http.dart\' as http; */
以上是关于Dart常用核心知识的主要内容,如果未能解决你的问题,请参考以下文章