@artman328
2022-05-19T14:46:45.000000Z
字数 14273
阅读 809
dart
Dart 是静态类型语言。
Dart 程序的入口是一个叫做 main 的函数。它有如下结构:
void main(){...}
Dart 程序的源代码文件以 .dart 为扩展名,它可以编译成操作系统本地机器码运行,也可编译成 JavaScript 语言代码有 JavaScript 解释器解释执行。
编译成本地代码有两种方式:JIT(Just In Time,即时编译) 和 AOT(Ahead Of Time,预先编译)。
JIT编译由 Dart 虚拟机载入源代码文件后,编译一句执行一句,直到执行完毕。
AOT 编译先将源代码文件编译成一个单独可执行的程序,需要时直接执行此程序即可。此执行程序可脱离 Dart 虚拟机运行(事实上,运行支撑环境已经被编译到可执行程序中了)。
(1)下载 Dart SDK
从 Dart 的官方网站下载 Dart 的 SDK(Software Development Kit,软件开发工具包),将其解压到某个文件夹,如:D:\dart-sdk。
(2)环境配置
为了能够在任何位置执行到 dart 的命令,应将 dart 所在路径添加到系统或用户环境变量 PATH。以下命令将其路径添加到用户环境变量 PATH。
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,输入以下内容:
void main(){print("Welcome to dart!");}
然后运行。如果看到输出:
Welcome to dart!
说明开发平台搭建成功。
(1)num (number, 数值)
数值型,包括整型(int)和双精度浮点型(double)。
数值型的文字表达是:100,0x98ef(十六进制), 1.23,2.35e-3(),5.67E5()等等。
void main(){print(0x98ef); // output: 39151print(2.35e-3); // output: 0.00235}
(2)String(字符串)
文字性信息是字符串类型。
字符串的文字表达,需要用引号括起来。如:
'单引号括起来的字符串'
"双引号括起来的字符串"
'单引号里有"双引号"是可以的'
"双引号里有'单引号'也是可以的"
"同级引号在文字里需要\"如此\"处理才行。"
void main(){print("Hello!"); // output: Hello!print('"No, thank you!", she said.'); // output: "No, thank you!", she said.print("\"No, thank you!\", she said."); // output: "No, thank you!", she said.}
(3)bool(布尔型,逻辑型)
布尔型的文字表达只有两个:true(真),false(假)。
void main(){print(true); // output: trueprint(false); // output: false}
(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 是个特殊的值,它表示这是个未知的、无意义的值。
变量(variable)是用于装载数据的命名容器,它对应着内存中某个存储位置。
变量命名规则:
1.变量只能由数字、字母、下划线和美元符($)组成;
2.注意:标识符开头不能是数字;
3.标识符不能是保留字和关键字;
4.变量的名字是区分大小写的;
5.标识符(变量名称)一定要见名思意“变量名称建议用名词,方法名称建议用动词。
变量声明时需要指明它能装载的数据类型(或 var, 指明让编译器根据第一次装载的数据来推断)。赋值是将数据装入变量容中。没有赋值的变量的值就是 null。如果允许一个变量的值是 null,在变量声明时就要说明,方法是在他的类型后加上一个问号。
以下是声明和赋值的例子。
Dart 是静态类型语言,是指变量只能装载指定的数据类型的数据。
num temperature; // 声明了一个用于装载数值(整数、小数均可)的容器,名称是 temperature。temperature = 37; // 赋值,将右边的 37 赋给左边的变量 temperaturetemperature = 37.5;int count;count = 10;count = 10.5; // 错double weight = 12; // 声明和赋值同时做了var name = "Billy"; // 编译器被要求自行推断变量 name 的类型。在此它会被推断为字符串类型。name = 12; // 错String? gender; // gender 可以是 nullbool isReady = false; //List data = [12.34,100,'OK',false];List<String> seasons = ['sparing','summer','fall','winter']; // <类型>用于指定装载的数据类型Set<String> colors = {'blue', 'green', 'red'};Map emp_info = {'name': 'Bill', 'age': 20, 'education': 'master'};
| 运算符 | 含义 | 举例 |
|---|---|---|
| + | 加 | 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 |
运算优先级:[*, /, %] > [+, -]
| 运算符 | 含义 | 举例 |
|---|---|---|
| + | 字符串相连 | "Hello, " + "Bill!" => "Hello, Bill!" |
| ${} | 变量替换 | var name= "Bill"; "Hello, ${name}!" => "Hello, Bill!" |
| 运算符 | 含义 | 举例 |
|---|---|---|
| + | 列表相连 | [1,2] + [3,4] => [1,2,3,4] |
比较运算的结果为 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 |
| != | 不等于 |
逻辑运算的操作数是 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 |
运算优先级:! > && > ||
位运算的操作数是整数,结果也是整数。数据位为 1 相当于 true,数据位为 0 相当于 false
| 运算符 | 含义 | 举例 |
|---|---|---|
| & | 按位与 | 138 & 15 => 10 (去高半字节,保留低半字节) 10001010 & 00001111 = 00001010 |
| | | 按位或 |
面向对象是一种编程方法。
在面向对象的编程方法中,程序需要处理的一切事物都是一种生命体,他有自己的特征和所属物,并且有处理自己事务的能力。
该编程方法的思想是:不同的事物之间的互动完成了一个业务过程。它模拟的是人类社会中各个个体(人或单位或部门)之间的互动完成了事务管理过程。这些个体在协作中通过互通消息、处理自己的数据并交换数据来完成事务的处理。
在社会生活中,这些个体根据自己的职责被划分成了不同的类别。比如:学校、警察局、工厂、教务处、人事部等。
以下是一个典型的业务过程:
将事物以特征进行分类描述,就构成类。比如以下是对“会议”这种事物所进行的描述:
它有这样一些属性:会议名称、会议地点、召开时间、时长、参会人员等;
它有这样一些行为:登记与会者、统计与会者、宣布开始、宣布结束等。
而以下是一个具体的会议的描述:
会议名称:2021年度董事会议
会议地点:公司第一会议室
召开时间:2021年12月31日上午9:00
时长:3小时
参会人员:所有董事会成员
……
我们把对一类事物的共同描述成为“类”(class),而把一类事物中的具体个体叫做“对象”(object),也可称为实例(instance)。
因此,以上对会议的描述就是对“会议类”的描述,名为“2021年度董事会议”的会议就是一个“会议类”的具体“对象”或“实例”。
事物的分类是具有层次结构的,比如:“交通工具”是一个“类”,“汽车”也是一个“类”,“越野车”也是一个“类”,他们就具有了一种所属关系:“越野车”属于“汽车”的下级分类(术语叫“子类”),而“汽车”有又属于“交通工具”的一个下级分类。以后我们会看到,这种关系叫“继承”(inheritance)。
在Dart 中,所有的数据都是某种数据类的一个对象。因为是类的对象,它们就有了自己的属性和行为。
在程序中查看一个对象的属性的语法是:对象.属性,可将“.”读作“的”,理解为“对象的属性”。
以下例子查看一个“双精度浮点数类(double)”的对象(temperature)的属性 isNegative (是否负值),用了temperature.isNegative(温度的是否负数属性):
void main(){double temperature = -18;print(temperature.isNegative); // output: true}
在程序中查看一个对象的属性的语法是:对象.属性,可将“.”读作“的”,理解为“对象的属性”。
在程序中让对象进行某个行为的语法是:对象.行为([数据]),其中的“数据”是传递给对象处理的数据,有的行为并不接收数据。
以下例子让一个 List 类的对象 colors 进行 add (添加)行为,并把数据 “blue” 传递给它。然后查看它的“length”(长度,数组中数据的个数)属性。
void main() {var colors = ["red", "green"];colors.add("blue");print(colors.length); // output: 3}
表达式是能够求出一个结果的代码。
如:amount = price * count; age>18;等。
语句是程序中一个完整的执行单元。语句可以是一条单独语句,也可以是多条语句构成的语句块(用大括号{}括住)。
Dart的语句以;号结束(语句块后面不需要分号)。
常见的语句有以下几种。
赋值语句用于给变量赋值:
变量 = 表达式;
作用是将右侧表达式的值赋予左侧的变量。
条件判断语句根据条件执行相应的语句或语句块。
if(条件){... // 如果条件满足执行此部分代码}else{... // 否则执行此部分代码}
条件判断语句可以按照逻辑进行多条件组合或嵌套。如:
if(条件1){...}else if(条件2){...}else if(条件3){...}...else{}
if(条件1){if(条件2){...}else{...}}else{...}
循环语句用于在某种条件下重复做某事。
它有以下几种形式。
a) 计数循环
如:
for(int i=0; i<10; i++){... // 循环体// 若碰到 continue; 语句,直接回到第 1 行// 若碰到 break; 语句,直接跳出循环到第5行以后}
循环过程:
b) 前置条件循环
while(条件满足){... // 循环体// 若碰到 continue; 语句,直接回到第 1 行// 若碰到 break; 语句,直接跳出循环到第5行以后}
循环过程:
b) 后置条件循环
do{... // 循环体// 若碰到 continue; 语句,直接回到第 1 行// 若碰到 break; 语句,直接跳出循环到第5行以后}while(条件);
循环过程:
根据表达式取值,决定执行的语句或语句块。
switch(表达式){case 取值1:...break;case 取值2:...break;case 取值3:...break;case 取值4:case 取值5:case 取值6:... // 取值4、取值45、取值46均执行此部分代码break;default:...}
函数,是完成某种功能(算法)的可重复使用的程序片断。
函数有三个要素:函数名、接收的参数和返回的数据类型。
以下语句定义了一个接收两个整型数据(对位传递的位置参数a和b)、并返回一个整型数的名为add的函数,用于得到两个整数的相加的值:
int add(int a, int b){return a + b;}void main(){print(add(10,20)); // output: 30// add(10,20) 为函数调用,// 参数对位传递:// 将10(实际参数)赋予参数a(形式参数), 20(实际参数)赋予参数b(形式参数)}
// 缺省参数写在最后,用[]号括住int sum(int a, int b, [int c = 0, int d = 0]){return a + b + c + d;}void main(){print(sum(10,20)); // output: 30print(sum(10,20,30)); // output: 60print(sum(10,20,30,40)); // output: 100}
命名参数需要在传递实际参数时指明形式参数的名称。
double get_payment(double price, {double discount:1.0, double deduction:0.0}){return price * discount - deduction;}void main(){print(get_payment(1000.00, deduction:100, discount:0.90)); // output : 800.0// ------- ------------- -------------// 位置参数 命名参数 命名参数}
如果函数体只是一个表达式,可用箭头形式的方式进行定义。
int add(int a, int b) => a + b;// 相当于:// int add(int a, int b){// return a + b;// }void main(){print(add(10,20));}
void main(){var data = [10,20,16,22,36];data.forEach((e)=>print(e));data.forEach((e){e = e*10;print(e);});}
类是一种自定义的数据类型。
class Company{String name = "";String address = "";String telephone = "";// 构造函数Company(String name, String address, String telephone){this.name = name;this.address = address;this.telephone = telephone;}// 另一个构造函数(带别名)Company.namedValues({String name:"", String address:"", String telephone:""}){this.name = name;this.address = address;this.telephone = telephone;}String describe(){return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";}}void main(){Company company1 = Company("New Tech 1","Northen Avenue #1900","1234-45678769");Company company2 = Company.namedValues(telephone:"1234-45678769",name:"New Tech 2",address:"Northen Avenue #1900");print(company1.describe());print(company2.describe());}
用构造函数简洁写法(short-hand)改写以上程序。
class Company{String name = "";String address = "";String telephone = "";// 构造函数Company(this.name, this.address, this.telephone);// 另一个构造函数(带别名)Company.namedValues({this.name:"", this.address:"", this.telephone:""});// 或 Company.namedValues({this.name="", this.address="", this.telephone=""});String describe(){return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";}}void main(){Company company1 = Company("New Tech 1","Northen Avenue #1900","1234-45678769");Company company2 = Company.namedValues(telephone:"1234-45678769",name:"New Tech 2",address:"Northen Avenue #1900");print(company1.describe());print(company2.describe());}
类的成员包括属性和方法。如果类的成员名称开始于下划线,它们对外界就是不可见的。
class Company {String name = "";String address = "";String telephone = "";Company(this.name, this.address, this.telephone);String describe(){return "Name: ${this.name}\nAddress: ${this.address}\nTelephone: ${this.telephone}";}}void main(){Company company = Company("","Northen Avenue #1900","1234-45678769");print(company.describe());// 以下随意修改成员变量company.name = "";company.address = "";company.telephone = "";print(company.describe());}
为避免直接访问成员变量(主要避免非法赋值、越权取值等):
class Company {String _name = "";String _address = "";String _telephone = "";// settervoid set name(String name){_checkEmpty("Name",name);_name = name;}// getterString get name => _name;void set address(String address){_checkEmpty("Address",address);_address = address;}String get address => _address;void set telephone(String telephone){_checkEmpty("Telephone",telephone);_telephone = telephone;}String get telephone => _telephone;void _checkEmpty(name,value){if(value.trim().isEmpty){throw new Exception("${name} can't be empty!");}}Company(String name, String address, String telephone){if(name.trim().isEmpty || address.trim().isEmpty || telephone.trim().isEmpty){throw Exception("All fields must not be empty!");}this._name = name;this._address = address;this._telephone = telephone;}String describe(){return "Name: ${this._name}\nAddress: ${this._address}\nTelephone: ${this._telephone}";}}void main(){Company company = Company("New Tech 1","Northen Avenue #1900","1234-45678769");//Company company = Company("","Northen Avenue #1900","1234-45678769");company.name = "";print(company.describe());}
类的继承可实现代码复用。
class Vehicle {String name = "";String brand = "";Vehicle(this.name, this.brand);String describe(){return "Vihecle: Name - ${this.name}, Brand - ${this.brand}";}}class Car extends Vehicle{int seatCount = 0;Car(String name, String brand, int seatCount):super(name,brand){this.seatCount = seatCount;}@overrideString describe(){return "Car: Name - ${this.name}, Brand - ${this.brand}, Seat Count - ${this.seatCount}";}}class Truck extends Vehicle{int loadInTons = 0;Truck(String name, String brand, int loadInTons):super(name,brand){this.loadInTons = loadInTons;}@overrideString describe(){return "Truck: Name - ${this.name}, Brand - ${this.brand}, Load - ${this.loadInTons} Tons";}}void main(){Car car = Car("CRV","HONDA",5);print(car.describe());Truck truck = Truck("BIG-FOOT","NISSAN",30);print(truck.describe());}
抽象类包含了一些无法实现的行为。
abstract class Shape{double area(); // 无法实现的抽象行为String describe(){ // 已实现有公共行为return "I'm one of shapes.";}}class Circle extends Shape{double radius = 0;Circle(this.radius);@overrridedouble area(){return radius * radius * 3.14;}}class Rectangle extends Shape{double length = 0;double width = 0;Rectangle(this.length, this.width);@overridedouble area(){return length * width;}}void main(){Circle circle = Circle(10);print(circle.area());Rectangle rectangle = Rectangle(10,10);print(rectangle.area());}
在 dart 中,任何类的定义都隐含一种接口(方法集合)定义。如果一个类要实现另外一个类,意味着它要自己实现这另一个类的所有方法。
abstract class Shape{double area();String describe(){ // 这个方法的实现不会被“实现者”使用return "I'm one of shapes.";}}class Circle implements Shape{double radius = 0;Circle(this.radius);double area(){return radius * radius * 3.14;}}class Rectangle implements Shape{double length = 0;double width = 0;Rectangle(this.length, this.width);double area(){return length * width;}}void main(){Circle circle = Circle(10);print(circle.area());print(circle.describe()); // ErrorRectangle rectangle = Rectangle(10,10);print(rectangle.area());print(rectangle.describe()); // Error;}
因此,可定义一个抽象类,在其中声明多个方法,作为一个让“实现者”遵循的契约:你要实现我,请实现我的所有方法!
可用父类(接口)声明的变量装载子类对象,从而实现同一方法进行不同的行为——多态。
注意:用父类变量装载子类对象后,子类对象特有的方法和属性将不可见。
abstract class Shape{double area();String describe();}class Circle extends Shape{double radius = 0;Circle(this.radius);@overridedouble area(){return radius * radius * 3.14;}@overrideString describe(){return "Circle: Radius - ${this.radius}";}}class Rectangle extends Shape{double length = 0;double width = 0;Rectangle(this.length, this.width);@overridedouble area(){return length * width;}@overrideString describe(){return "Rectangle: Length - ${this.length}, Width - ${this.width}";}}void main(){List<Shape> shapes = [];Circle circle1 = Circle(10);Rectangle rectangle1 = Rectangle(10,10);Circle circle2 = Circle(12);Rectangle rectangle2 = Rectangle(12,12);Circle circle3 = Circle(14);Rectangle rectangle3 = Rectangle(14,14);shapes.addAll([circle1,rectangle1,circle2,rectangle2,circle3,rectangle3]);shapes.forEach((s){print(s.area());print(s.describe());});}
用父类(接口)装载子类对象,可方便实现对象替换,从而灵活地实现功能替换。
以下程序中,只要把实现了 OutputDevice 类的接口的对象传递给 Article,它就会调用对象的 output 方法进行输出。
class Article {String text = "";OutputDevice? outputDevice;Article(this.text, this.outputDevice);void output(){this.outputDevice?.output();}}abstract class OutputDevice{void output();}class Printer implements OutputDevice{void output(){print("Output to a printer!");}}class Screen implements OutputDevice{void output(){print("Output to the screen!");}}void main(){OutputDevice printer = Printer();OutputDevice screen = Screen();Article article1 = Article("Hello!", printer);article1.output();Article article2 = Article("Hello!", screen);article2.output();}
Dart属于单继承,所有类的顶级类实 object 类。
下级类继承了上级类的所有特性(属性和行为)。
import 'package:http/http.dart' as http;import 'package:http/retry.dart';Future<void> main() async {final client = RetryClient(http.Client());try {print(await client.read(Uri.parse('http://www.163.com')));} finally {client.close();}}
SELECT id, name, tavg, salaryFROM (SELECT id, name, salary,AVG(salary) AS avg_salaryFROM employeesGROUP BY id) sre,(SELECT (AVG(salary)) AS tavgFROM employees) taWHERE sre.avg_salary > ta.tavg;
SELECT name, price, havgFROM (SELECT name, price, AVG(price) AS avg_priceFROM bookGROUP BY name) tab1,(SELECT (AVG(price)) AS havgFROM book) tab2WHERE tab1.avg_price=tab2.havg;