[关闭]
@artman328 2022-05-19T14:46:45.000000Z 字数 14273 阅读 613

Dart 语言编程

dart


第一章 Dart 语言介绍与开发平台搭建

1.1 Dart 语言介绍

Dart 是静态类型语言。
Dart 程序的入口是一个叫做 main 的函数。它有如下结构:

  1. void main(){
  2. ...
  3. }

Dart 程序的源代码文件以 .dart 为扩展名,它可以编译成操作系统本地机器码运行,也可编译成 JavaScript 语言代码有 JavaScript 解释器解释执行。
编译成本地代码有两种方式:JIT(Just In Time,即时编译) 和 AOT(Ahead Of Time,预先编译)。
JIT编译由 Dart 虚拟机载入源代码文件后,编译一句执行一句,直到执行完毕。
AOT 编译先将源代码文件编译成一个单独可执行的程序,需要时直接执行此程序即可。此执行程序可脱离 Dart 虚拟机运行(事实上,运行支撑环境已经被编译到可执行程序中了)。

1.2 开发环境的配置

(1)下载 Dart SDK
从 Dart 的官方网站下载 Dart 的 SDK(Software Development Kit,软件开发工具包),将其解压到某个文件夹,如:D:\dart-sdk
(2)环境配置
为了能够在任何位置执行到 dart 的命令,应将 dart 所在路径添加到系统或用户环境变量 PATH。以下命令将其路径添加到用户环境变量 PATH。

  1. setx PATH "D:\dart-sdk\bin;%PATH%"

(3)安装程序编辑器
Visual Studio Code 官网 下载 Visual Studio Code,安装。
打开 Visual Studio Code,安装 dart 插件。
(4)测试开发环境
创建一个文件夹(如:D:\DartWork),用 Visual Studio Code 打开,在其中创建一个文件,如:test.dart,输入以下内容:

  1. void main(){
  2. print("Welcome to dart!");
  3. }

然后运行。如果看到输出:
Welcome to dart!
说明开发平台搭建成功。

第二章 Dart 语言的数据及其运算

2.1 Dart 的数据类型

(1)num (number, 数值)
数值型,包括整型(int)和双精度浮点型(double)。
数值型的文字表达是:100,0x98ef(十六进制), 1.23,2.35e-3(),5.67E5()等等。

  1. void main(){
  2. print(0x98ef); // output: 39151
  3. print(2.35e-3); // output: 0.00235
  4. }

(2)String(字符串)
文字性信息是字符串类型。
字符串的文字表达,需要用引号括起来。如:
'单引号括起来的字符串'
"双引号括起来的字符串"
'单引号里有"双引号"是可以的'
"双引号里有'单引号'也是可以的"
"同级引号在文字里需要\"如此\"处理才行。"

  1. void main(){
  2. print("Hello!"); // output: Hello!
  3. print('"No, thank you!", she said.'); // output: "No, thank you!", she said.
  4. print("\"No, thank you!\", she said."); // output: "No, thank you!", she said.
  5. }

(3)bool(布尔型,逻辑型)
布尔型的文字表达只有两个:true(真),false(假)。

  1. void main(){
  2. print(true); // output: true
  3. print(false); // output: false
  4. }

(4)list(列表,数组)
列表是一组数据(可限定所有单个数据的统一类型)。文字表达:用[]将一组数据括起来,单个数据之间用逗号分隔。如:
[12,56,23,33,56,109,'ok']
["Hello","Hi",100,"What's up","Hello"]
(5)set(集合)
集合是一组不重复的数据(可限定所有单个数据的统一类型)。文字表达:用{}将一组数据括起来,单个数据之间用逗号分隔。如:
{'ok',12,56,23,false,33,109}
{"Hello","Hi","What's up",true,100}
(6)map(映射)
映射在有的语言里称为字典、对象等。它是一组名称和值构成的数据,如:
{'name':'Billy','gender':'Male','birth_date':'1999-12-31','salary':3000}
(7)null
null 是个特殊的值,它表示这是个未知的、无意义的值。

2.1 变量

变量(variable)是用于装载数据的命名容器,它对应着内存中某个存储位置。
变量命名规则:

1.变量只能由数字、字母、下划线和美元符($)组成;

2.注意:标识符开头不能是数字;

3.标识符不能是保留字和关键字;

4.变量的名字是区分大小写的;

5.标识符(变量名称)一定要见名思意“变量名称建议用名词,方法名称建议用动词。

2.2 变量的声明与赋值

变量声明时需要指明它能装载的数据类型(或 var, 指明让编译器根据第一次装载的数据来推断)。赋值是将数据装入变量容中。没有赋值的变量的值就是 null。如果允许一个变量的值是 null,在变量声明时就要说明,方法是在他的类型后加上一个问号。
以下是声明和赋值的例子。
Dart 是静态类型语言,是指变量只能装载指定的数据类型的数据。

  1. num temperature; // 声明了一个用于装载数值(整数、小数均可)的容器,名称是 temperature。
  2. temperature = 37; // 赋值,将右边的 37 赋给左边的变量 temperature
  3. temperature = 37.5;
  4. int count;
  5. count = 10;
  6. count = 10.5; // 错
  7. double weight = 12; // 声明和赋值同时做了
  8. var name = "Billy"; // 编译器被要求自行推断变量 name 的类型。在此它会被推断为字符串类型。
  9. name = 12; // 错
  10. String? gender; // gender 可以是 null
  11. bool isReady = false; //
  12. List data = [12.34,100,'OK',false];
  13. List<String> seasons = ['sparing','summer','fall','winter']; // <类型>用于指定装载的数据类型
  14. Set<String> colors = {'blue', 'green', 'red'};
  15. Map emp_info = {'name': 'Bill', 'age': 20, 'education': 'master'};

2.3 Dart 数据的基本运算

1、数值运算

运算符 含义 举例
+ 2 + 2 => 4
- 100 - 80 => 20
* 2 * 10 => 20
/ 100 / 20 => 5
% 模除,取余 33 % 10 => 3
+= 累加(a += b 相当于 a = a + b) int a = 10; a+=5; a=>15
-= 递减(a -= b 相当于 a = a - b) int b = 10; b-=5; b=>5
++ 增1 (a++ 相当于 a = a + 1) int a=10; a++; a=>11
-- 减1 (a-- 相当于 a = a - 1) int a=10; a--; a=>9

运算优先级:[*, /, %] > [+, -]

2、字符串运算

运算符 含义 举例
+ 字符串相连 "Hello, " + "Bill!" => "Hello, Bill!"
${} 变量替换 var name= "Bill"; "Hello, ${name}!" => "Hello, Bill!"

3、列表(数组)(List)运算

运算符 含义 举例
+ 列表相连 [1,2] + [3,4] => [1,2,3,4]

2.4 Dart 数据的比较运算

比较运算的结果为 bool 型数据:true(真) 或 false(假)。

运算符 含义 举例
> 大于 5.6>5 => true
5.6<5 => false
>= 大于或等于 100>=100 => true
100>=101 => false
< 小于
<= 小于或等于
== 等于 123==123 => true
123==123.00 => true
"Hello"=="Hello" => true
[1,2,3]==[1,2,3] => false
{1,2,3}=={1,2,3} => false
{'a':1,'b':2,'c':3}=={'a':1,'b':2,'c':3} => false
!= 不等于

2.5 Dart 数据的逻辑运算

逻辑运算的操作数是 bool 型数据:true(真) 或 false(假)。
逻辑运算的结果为 bool 型数据:true(真) 或 false(假)。

运算符 含义 举例
&& 与,并且 true && true => true 相当于 1 × 1 = 1
true && false => false 相当于 1 × 0 = 0
false && true => false 相当于 0 × 1 = 0
false && false => false 相当于 0 × 0 = 0
结论:全真才真
|| 或,或者 true || true => true 相当于 1 + 1 = 1(非零就是真)
true || false => true 相当于 1 + 0 = 1
false || true => true 相当于 0 + 1 = 1
false || false => false 相当于 0 + 0 = 0
结论:全假才假
! 非,取反 !true => false
!false => true

运算优先级:! > && > ||

2.6 Dart 数据的位运算

位运算的操作数是整数,结果也是整数。数据位为 1 相当于 true,数据位为 0 相当于 false

运算符 含义 举例
& 按位与 138 & 15 => 10 (去高半字节,保留低半字节)
10001010 &
00001111 =
00001010
| 按位或

第三章 Dart 的面向对象初步

面向对象是一种编程方法。
在面向对象的编程方法中,程序需要处理的一切事物都是一种生命体,他有自己的特征和所属物,并且有处理自己事务的能力。
该编程方法的思想是:不同的事物之间的互动完成了一个业务过程。它模拟的是人类社会中各个个体(人或单位或部门)之间的互动完成了事务管理过程。这些个体在协作中通过互通消息、处理自己的数据并交换数据来完成事务的处理。
在社会生活中,这些个体根据自己的职责被划分成了不同的类别。比如:学校、警察局、工厂、教务处、人事部等。

以下是一个典型的业务过程:

  1. “新兴”公司总经理办公室通知人事部需要招聘一名法律顾问并提出资格要求;
  2. 人事部向招聘媒体发出招聘信息;
  3. 人事部挑选应聘人员;
  4. 人事部对挑选出的人员进行面试;
  5. 人事部将面试合格者资料提交总经理办公室进行审核;
  6. 总经理办公室审核面试合格证者资格;
  7. 总经理办公室通知人事部审核通过(如未通过,返回第2或第3步);
  8. 人事部将该人员资料入档;
  9. 人事部通知法务部新人入职;
  10. 法务部为新人建立工作档案。

3.1 类和对象

将事物以特征进行分类描述,就构成类。比如以下是对“会议”这种事物所进行的描述:
它有这样一些属性:会议名称、会议地点、召开时间、时长、参会人员等;
它有这样一些行为:登记与会者、统计与会者、宣布开始、宣布结束等。
而以下是一个具体的会议的描述:
会议名称:2021年度董事会议
会议地点:公司第一会议室
召开时间:2021年12月31日上午9:00
时长:3小时
参会人员:所有董事会成员
……

我们把对一类事物的共同描述成为“类”(class),而把一类事物中的具体个体叫做“对象”(object),也可称为实例(instance)。
因此,以上对会议的描述就是对“会议类”的描述,名为“2021年度董事会议”的会议就是一个“会议类”的具体“对象”或“实例”。

事物的分类是具有层次结构的,比如:“交通工具”是一个“类”,“汽车”也是一个“类”,“越野车”也是一个“类”,他们就具有了一种所属关系:“越野车”属于“汽车”的下级分类(术语叫“子类”),而“汽车”有又属于“交通工具”的一个下级分类。以后我们会看到,这种关系叫“继承”(inheritance)。

3.1 Dart 数据对象

在Dart 中,所有的数据都是某种数据类的一个对象。因为是类的对象,它们就有了自己的属性和行为。

1、查看数据对象的属性

在程序中查看一个对象的属性的语法是:对象.属性,可将“.”读作“的”,理解为“对象的属性”。
以下例子查看一个“双精度浮点数类(double)”的对象(temperature)的属性 isNegative (是否负值),用了temperature.isNegative(温度的是否负数属性):

  1. void main(){
  2. double temperature = -18;
  3. print(temperature.isNegative); // output: true
  4. }

在程序中查看一个对象的属性的语法是:对象.属性,可将“.”读作“的”,理解为“对象的属性”。

2、让对象进行某个行为

在程序中让对象进行某个行为的语法是:对象.行为([数据]),其中的“数据”是传递给对象处理的数据,有的行为并不接收数据。
以下例子让一个 List 类的对象 colors 进行 add (添加)行为,并把数据 “blue” 传递给它。然后查看它的“length”(长度,数组中数据的个数)属性。

  1. void main() {
  2. var colors = ["red", "green"];
  3. colors.add("blue");
  4. print(colors.length); // output: 3
  5. }

第四章 Dart 的表达式和语句

4.1 表达式(expresion)

表达式是能够求出一个结果的代码。
如:amount = price * count; age>18;等。

4.1 语句(statement)

语句是程序中一个完整的执行单元。语句可以是一条单独语句,也可以是多条语句构成的语句块(用大括号{}括住)。
Dart的语句以;号结束(语句块后面不需要分号)。
常见的语句有以下几种。

(1)赋值语句

赋值语句用于给变量赋值:
变量 = 表达式;
作用是将右侧表达式的值赋予左侧的变量。

(2)条件判断语句

条件判断语句根据条件执行相应的语句或语句块。

  1. if(条件){
  2. ... // 如果条件满足执行此部分代码
  3. }
  4. else{
  5. ... // 否则执行此部分代码
  6. }

条件判断语句可以按照逻辑进行多条件组合或嵌套。如:

  1. if(条件1){
  2. ...
  3. }
  4. else if(条件2){
  5. ...
  6. }
  7. else if(条件3){
  8. ...
  9. }
  10. ...
  11. else{
  12. }
  1. if(条件1){
  2. if(条件2){
  3. ...
  4. }
  5. else{
  6. ...
  7. }
  8. }
  9. else{
  10. ...
  11. }

(3)循环语句

循环语句用于在某种条件下重复做某事。
它有以下几种形式。
a) 计数循环
如:

  1. for(int i=0; i<10; i++){
  2. ... // 循环体
  3. // 若碰到 continue; 语句,直接回到第 1 行
  4. // 若碰到 break; 语句,直接跳出循环到第5行以后
  5. }

循环过程:

Created with Raphaël 2.1.2开始初始化计数器:i=0循环条件 i<10 满足?循环体计数器变更:i++结束yesno

b) 前置条件循环

  1. while(条件满足){
  2. ... // 循环体
  3. // 若碰到 continue; 语句,直接回到第 1 行
  4. // 若碰到 break; 语句,直接跳出循环到第5行以后
  5. }

循环过程:

Created with Raphaël 2.1.2开始循环条件满足?循环体结束yesno

b) 后置条件循环

  1. do{
  2. ... // 循环体
  3. // 若碰到 continue; 语句,直接回到第 1 行
  4. // 若碰到 break; 语句,直接跳出循环到第5行以后
  5. }while(条件);

循环过程:

Created with Raphaël 2.1.2开始循环体循环条件满足?结束yesno

(4)switch 语句

根据表达式取值,决定执行的语句或语句块。

  1. switch(表达式){
  2. case 取值1:
  3. ...
  4. break;
  5. case 取值2:
  6. ...
  7. break;
  8. case 取值3:
  9. ...
  10. break;
  11. case 取值4:
  12. case 取值5:
  13. case 取值6:
  14. ... // 取值4、取值45、取值46均执行此部分代码
  15. break;
  16. default:
  17. ...
  18. }

第五章 Dart 的函数

函数,是完成某种功能(算法)的可重复使用的程序片断。
函数有三个要素:函数名、接收的参数和返回的数据类型。

5.1 函数的定义

(1)函数定义

以下语句定义了一个接收两个整型数据(对位传递的位置参数a和b)、并返回一个整型数的名为add的函数,用于得到两个整数的相加的值:

  1. int add(int a, int b){
  2. return a + b;
  3. }
  4. void main(){
  5. print(add(10,20)); // output: 30
  6. // add(10,20) 为函数调用,
  7. // 参数对位传递:
  8. // 将10(实际参数)赋予参数a(形式参数), 20(实际参数)赋予参数b(形式参数)
  9. }

(2)带缺省参数的函数定义:

  1. // 缺省参数写在最后,用[]号括住
  2. int sum(int a, int b, [int c = 0, int d = 0]){
  3. return a + b + c + d;
  4. }
  5. void main(){
  6. print(sum(10,20)); // output: 30
  7. print(sum(10,20,30)); // output: 60
  8. print(sum(10,20,30,40)); // output: 100
  9. }

(3)带命名参数函数的定义

命名参数需要在传递实际参数时指明形式参数的名称。

  1. double get_payment(double price, {double discount:1.0, double deduction:0.0}){
  2. return price * discount - deduction;
  3. }
  4. void main(){
  5. print(get_payment(1000.00, deduction:100, discount:0.90)); // output : 800.0
  6. // ------- ------------- -------------
  7. // 位置参数 命名参数 命名参数
  8. }

(4)箭头函数定义

如果函数体只是一个表达式,可用箭头形式的方式进行定义。

  1. int add(int a, int b) => a + b;
  2. // 相当于:
  3. // int add(int a, int b){
  4. // return a + b;
  5. // }
  6. void main(){
  7. print(add(10,20));
  8. }

(5)匿名函数定义

  1. void main(){
  2. var data = [10,20,16,22,36];
  3. data.forEach((e)=>print(e));
  4. data.forEach(
  5. (e){
  6. e = e*10;
  7. print(e);
  8. }
  9. );
  10. }

第六章 Dart 的类

6.1 类定义

类是一种自定义的数据类型。

  1. class Company{
  2. String name = "";
  3. String address = "";
  4. String telephone = "";
  5. // 构造函数
  6. Company(String name, String address, String telephone){
  7. this.name = name;
  8. this.address = address;
  9. this.telephone = telephone;
  10. }
  11. // 另一个构造函数(带别名)
  12. Company.namedValues({String name:"", String address:"", String telephone:""}){
  13. this.name = name;
  14. this.address = address;
  15. this.telephone = telephone;
  16. }
  17. String describe(){
  18. return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";
  19. }
  20. }
  21. void main(){
  22. Company company1 = Company("New Tech 1","Northen Avenue #1900","1234-45678769");
  23. Company company2 = Company.namedValues(
  24. telephone:"1234-45678769",
  25. name:"New Tech 2",
  26. address:"Northen Avenue #1900"
  27. );
  28. print(company1.describe());
  29. print(company2.describe());
  30. }

用构造函数简洁写法(short-hand)改写以上程序。

  1. class Company{
  2. String name = "";
  3. String address = "";
  4. String telephone = "";
  5. // 构造函数
  6. Company(this.name, this.address, this.telephone);
  7. // 另一个构造函数(带别名)
  8. Company.namedValues({this.name:"", this.address:"", this.telephone:""});
  9. // 或 Company.namedValues({this.name="", this.address="", this.telephone=""});
  10. String describe(){
  11. return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";
  12. }
  13. }
  14. void main(){
  15. Company company1 = Company("New Tech 1","Northen Avenue #1900","1234-45678769");
  16. Company company2 = Company.namedValues(
  17. telephone:"1234-45678769",
  18. name:"New Tech 2",
  19. address:"Northen Avenue #1900"
  20. );
  21. print(company1.describe());
  22. print(company2.describe());
  23. }

6.2 隐藏类成员(封装)

类的成员包括属性和方法。如果类的成员名称开始于下划线,它们对外界就是不可见的。

  1. class Company {
  2. String name = "";
  3. String address = "";
  4. String telephone = "";
  5. Company(this.name, this.address, this.telephone);
  6. String describe(){
  7. return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";
  8. }
  9. }
  10. void main(){
  11. Company company = Company("","Northen Avenue #1900","1234-45678769");
  12. print(company.describe());
  13. // 以下随意修改成员变量
  14. company.name = "";
  15. company.address = "";
  16. company.telephone = "";
  17. print(company.describe());
  18. }

为避免直接访问成员变量(主要避免非法赋值、越权取值等):

  1. class Company {
  2. String _name = "";
  3. String _address = "";
  4. String _telephone = "";
  5. // setter
  6. void set name(String name){
  7. _checkEmpty("Name",name);
  8. _name = name;
  9. }
  10. // getter
  11. String get name => _name;
  12. void set address(String address){
  13. _checkEmpty("Address",address);
  14. _address = address;
  15. }
  16. String get address => _address;
  17. void set telephone(String telephone){
  18. _checkEmpty("Telephone",telephone);
  19. _telephone = telephone;
  20. }
  21. String get telephone => _telephone;
  22. void _checkEmpty(name,value){
  23. if(value.trim().isEmpty){
  24. throw new Exception("${name} can't be empty!");
  25. }
  26. }
  27. Company(String name, String address, String telephone){
  28. if(name.trim().isEmpty || address.trim().isEmpty || telephone.trim().isEmpty){
  29. throw Exception("All fields must not be empty!");
  30. }
  31. this._name = name;
  32. this._address = address;
  33. this._telephone = telephone;
  34. }
  35. String describe(){
  36. return "Name: ${this._name}\nAddress: ${this._address}\nTelephone: ${this._telephone}";
  37. }
  38. }
  39. void main(){
  40. Company company = Company("New Tech 1","Northen Avenue #1900","1234-45678769");
  41. //Company company = Company("","Northen Avenue #1900","1234-45678769");
  42. company.name = "";
  43. print(company.describe());
  44. }

6.3 类的继承

类的继承可实现代码复用。

(1)继承的实现

  1. class Vehicle {
  2. String name = "";
  3. String brand = "";
  4. Vehicle(this.name, this.brand);
  5. String describe(){
  6. return "Vihecle: Name - ${this.name}, Brand - ${this.brand}";
  7. }
  8. }
  9. class Car extends Vehicle{
  10. int seatCount = 0;
  11. Car(String name, String brand, int seatCount):super(name,brand){
  12. this.seatCount = seatCount;
  13. }
  14. @override
  15. String describe(){
  16. return "Car: Name - ${this.name}, Brand - ${this.brand}, Seat Count - ${this.seatCount}";
  17. }
  18. }
  19. class Truck extends Vehicle{
  20. int loadInTons = 0;
  21. Truck(String name, String brand, int loadInTons):super(name,brand){
  22. this.loadInTons = loadInTons;
  23. }
  24. @override
  25. String describe(){
  26. return "Truck: Name - ${this.name}, Brand - ${this.brand}, Load - ${this.loadInTons} Tons";
  27. }
  28. }
  29. void main(){
  30. Car car = Car("CRV","HONDA",5);
  31. print(car.describe());
  32. Truck truck = Truck("BIG-FOOT","NISSAN",30);
  33. print(truck.describe());
  34. }

(2)抽象类

抽象类包含了一些无法实现的行为。

  1. abstract class Shape{
  2. double area(); // 无法实现的抽象行为
  3. String describe(){ // 已实现有公共行为
  4. return "I'm one of shapes.";
  5. }
  6. }
  7. class Circle extends Shape{
  8. double radius = 0;
  9. Circle(this.radius);
  10. @overrride
  11. double area(){
  12. return radius * radius * 3.14;
  13. }
  14. }
  15. class Rectangle extends Shape{
  16. double length = 0;
  17. double width = 0;
  18. Rectangle(this.length, this.width);
  19. @override
  20. double area(){
  21. return length * width;
  22. }
  23. }
  24. void main(){
  25. Circle circle = Circle(10);
  26. print(circle.area());
  27. Rectangle rectangle = Rectangle(10,10);
  28. print(rectangle.area());
  29. }

(3)接口

在 dart 中,任何类的定义都隐含一种接口(方法集合)定义。如果一个类要实现另外一个类,意味着它要自己实现这另一个类的所有方法。

  1. abstract class Shape{
  2. double area();
  3. String describe(){ // 这个方法的实现不会被“实现者”使用
  4. return "I'm one of shapes.";
  5. }
  6. }
  7. class Circle implements Shape{
  8. double radius = 0;
  9. Circle(this.radius);
  10. double area(){
  11. return radius * radius * 3.14;
  12. }
  13. }
  14. class Rectangle implements Shape{
  15. double length = 0;
  16. double width = 0;
  17. Rectangle(this.length, this.width);
  18. double area(){
  19. return length * width;
  20. }
  21. }
  22. void main(){
  23. Circle circle = Circle(10);
  24. print(circle.area());
  25. print(circle.describe()); // Error
  26. Rectangle rectangle = Rectangle(10,10);
  27. print(rectangle.area());
  28. print(rectangle.describe()); // Error;
  29. }

因此,可定义一个抽象类,在其中声明多个方法,作为一个让“实现者”遵循的契约:你要实现我,请实现我的所有方法!

(4)父类变量装载子类对象(多态实现)

可用父类(接口)声明的变量装载子类对象,从而实现同一方法进行不同的行为——多态。
注意:用父类变量装载子类对象后,子类对象特有的方法和属性将不可见。

  1. abstract class Shape{
  2. double area();
  3. String describe();
  4. }
  5. class Circle extends Shape{
  6. double radius = 0;
  7. Circle(this.radius);
  8. @override
  9. double area(){
  10. return radius * radius * 3.14;
  11. }
  12. @override
  13. String describe(){
  14. return "Circle: Radius - ${this.radius}";
  15. }
  16. }
  17. class Rectangle extends Shape{
  18. double length = 0;
  19. double width = 0;
  20. Rectangle(this.length, this.width);
  21. @override
  22. double area(){
  23. return length * width;
  24. }
  25. @override
  26. String describe(){
  27. return "Rectangle: Length - ${this.length}, Width - ${this.width}";
  28. }
  29. }
  30. void main(){
  31. List<Shape> shapes = [];
  32. Circle circle1 = Circle(10);
  33. Rectangle rectangle1 = Rectangle(10,10);
  34. Circle circle2 = Circle(12);
  35. Rectangle rectangle2 = Rectangle(12,12);
  36. Circle circle3 = Circle(14);
  37. Rectangle rectangle3 = Rectangle(14,14);
  38. shapes.addAll([circle1,rectangle1,circle2,rectangle2,circle3,rectangle3]);
  39. shapes.forEach((s){
  40. print(s.area());
  41. print(s.describe());
  42. });
  43. }

用父类(接口)装载子类对象,可方便实现对象替换,从而灵活地实现功能替换。
以下程序中,只要把实现了 OutputDevice 类的接口的对象传递给 Article,它就会调用对象的 output 方法进行输出。

  1. class Article {
  2. String text = "";
  3. OutputDevice? outputDevice;
  4. Article(this.text, this.outputDevice);
  5. void output(){
  6. this.outputDevice?.output();
  7. }
  8. }
  9. abstract class OutputDevice{
  10. void output();
  11. }
  12. class Printer implements OutputDevice{
  13. void output(){
  14. print("Output to a printer!");
  15. }
  16. }
  17. class Screen implements OutputDevice{
  18. void output(){
  19. print("Output to the screen!");
  20. }
  21. }
  22. void main(){
  23. OutputDevice printer = Printer();
  24. OutputDevice screen = Screen();
  25. Article article1 = Article("Hello!", printer);
  26. article1.output();
  27. Article article2 = Article("Hello!", screen);
  28. article2.output();
  29. }

第七章 类间关系

7.1 继承(Inheritance)

Dart属于单继承,所有类的顶级类实 object 类。
下级类继承了上级类的所有特性(属性和行为)。

7.2 实现(Implementation)

7.3 组合(Composition)

7.4 聚合(Aggregation)

第七章 Dart 语言的包

7.1 Dart 程序项目

7.2 Dart 的依赖管理

  1. import 'package:http/http.dart' as http;
  2. import 'package:http/retry.dart';
  3. Future<void> main() async {
  4. final client = RetryClient(http.Client());
  5. try {
  6. print(await client.read(Uri.parse('http://www.163.com')));
  7. } finally {
  8. client.close();
  9. }
  10. }

第八章 Flutter 介绍

  1. SELECT id, name, tavg, salary
  2. FROM (SELECT id, name, salary,
  3. AVG(salary) AS avg_salary
  4. FROM employees
  5. GROUP BY id) sre,
  6. (SELECT (AVG(salary)) AS tavg
  7. FROM employees) ta
  8. WHERE sre.avg_salary > ta.tavg
  9. ;
  1. SELECT name, price, havg
  2. FROM (SELECT name, price, AVG(price) AS avg_price
  3. FROM book
  4. GROUP BY name) tab1,
  5. (SELECT (AVG(price)) AS havg
  6. FROM book) tab2
  7. WHERE tab1.avg_price=tab2.havg
  8. ;
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注