当前位置:网站首页>Flutter基础学习(一)Dart语言入门
Flutter基础学习(一)Dart语言入门
2022-08-01 21:55:00 【长安不及十里】
一 基本介绍
1.1 概述
- 官网:https://dart.cn/
- Dart 是一个为全平台构建快速应用的客户端优化的编程语言。
- Dart 是谷歌开发的计算机编程语言,被应用于 Web、服务器、移动应用和物联网等领域的开发。Dart 是面向对象、类定义的、单继承的语言。它的语法类似C语言,可以转译为 JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型(reified generics)、可选类型(optional typing)和sound type system。
1.2 基本环境搭建
- SDK下载:https://dart.cn/get-dart/archive
- DART_SDK:自己的解压路径
- Path: 自己的解压路径
- 验证:Dart --version
1.3 代码工具
- VsCode
- 插件
- 编写第一个入门应用
/*
* @Description: hello.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-29 18:46:23
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-29 18:46:37
*/
void main() {
print('hello world');
}
1.4 重要概念
- 所有变量引用的都是 对象,每个对象都是一个 类 的实例。数字、函数以及 null 都是对象。除去 null 以外(如果你开启了 空安全), 所有的类都继承于 Object 类。
- 尽管 Dart 是强类型语言,但是在声明变量时指定类型是可选的,因为 Dart 可以进行类型推断。在上述代码中,变量 number 的类型被推断为 int 类型。
- 如果你开启了 空安全,变量在未声明为可空类型时不能为 null。你可以通过在类型后加上问号 (?) 将类型声明为可空。例如,int? 类型的变量可以是整形数字或 null。如果你 明确知道 一个表达式不会为空,但 Dart 不这么认为时,你可以在表达式后添加 ! 来断言表达式不为空(为空时将抛出异常)。例如:int x = nullableButNotNullInt!
- 如果你想要显式地声明允许任意类型,使用 Object?(如果你 开启了空安全)、 Object 或者 特殊类型dynamic 将检查延迟到运行时进行。
- Dart 支持泛型,比如 List(表示一组由 int 对象组成的列表)或 List(表示一组由任何类型对象组成的列表)。
- Dart 支持顶级函数(例如 main 方法),同时还支持定义属于类或对象的函数(即 静态 和 实例方法)。你还可以在函数中定义函数(嵌套 或 局部函数)。
- Dart 支持顶级 变量,以及定义属于类或对象的变量(静态和实例变量)。实例变量有时称之为域或属性。
- Dart 没有类似于 Java 那样的 public、protected 和 private 成员访问限定符。如果一个标识符以下划线 (_) 开头则表示该标识符在库内是私有的。可以查阅 库和可见性 获取更多相关信息。
- 标识符 可以以字母或者下划线 (_) 开头,其后可跟字符和数字的组合。
- Dart 中 表达式 和 语句 是有区别的,表达式有值而语句没有。比如条件表达式 expression condition ? expr1 : expr2 中含有值 expr1 或 expr2。与 if-else 分支语句相比,if-else 分支语句则没有值。一个语句通常包含一个或多个表达式,但是一个表达式不能只包含一个语句。
- Dart 工具可以显示 警告 和 错误 两种类型的问题。警告表明代码可能有问题但不会阻止其运行。错误分为编译时错误和运行时错误;编译时错误代码无法运行;运行时错误会在代码运行时导致 异常。
二 基本语法
2.1 变量
- 变量是一个引用,根据Dart中万物皆对象原则,即变量存储的都是对象的引用,或者说它们都是指向对象。
- 变量不能以数字开头。
- 变量不能是关键字。
- 变量有数字,字母,下划线组成。
- 变量区分大小写,且含义不同。
- 声明可以有两种方式,一种是不指定类型,即使用var关键字。
- 因为有类型推导,所以两种实现效果一样,官方推荐在函数内的本地变量尽量使用var声明。
- 在 Dart 中,未初始化以及可空类型的变量拥有一个默认的初始值 null。(如果你未迁移至 空安全,所有变量都为可空类型。)即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。
/*
* @Description: 变量.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-29 19:04:54
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-29 19:05:55
*/
void main() {
// 第一种:不指定变量类型
var name = 'shu';
print(name);
// 第二种:指定变量类型
String name2 = 'shu';
print(name2);
}
2.2 常量
- 使用过程中从来不会被修改的变量, 可以使用 final 或 const,而不是 var 或者其他类型,Final 变量的值只能被设置一次; Const 变量在编译时就已经固定 (Const 变量 是隐式 Final 的类型) 。最高级 final 变量或类变量在第一次使用时被初始化。
- 提示: 实例变量可以是 final 类型但不能是 const 类型。 必须在构造函数体执行之前初始化 final 实例变量 —— 在变量声明中,参数构造函数中或构造函数的初始化列表中进行初始化。
/*
* @Description:常量.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-29 19:10:07
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-29 19:10:08
*/
void main() {
//const 常量
const PI = 3.14;
print(PI);
// final 常量
final name = 'shu';
print(name);
}
2.3 数据类型(内置类型)
Dart 语言支持以下数据类型:
- Number
- String
- Boolean
- List (也被称为 Array)
- Map
- Set
- Rune (不常用)
- Symbol(不常用)
2.3.1 String
- Dart 字符串是一组 UTF-16 单元序列。 字符串通过单引号或者双引号创建。
- 字符串可以通过 ${expression} 的方式内嵌表达式。 如果表达式是一个标识符,则 {} 可以省略。 在 Dart 中通过调用就对象的 toString() 方法来得到对象相应的字符串。
- 使用三个单引号或者三个双引号也能创建多行字符串
/*
* @Description:数据类型.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-29 19:28:36
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-29 20:06:27
*/
void main(List<String> args) {
// 指定类型字符串形式
String name = 'shu';
print(name);
// 字符串形式
var name2 = 'shu';
print(name2);
// 字符串的拼接
var name3 = 'shu' + 'shu';
print(name3);
// ${expression}
var s = 'string interpolation';
print('${s}');
// 字符串截取
print(s.substring(2));
// 应该说字符串的常用方法,都基本拥有
// 代码中文解释
var s1 = '''
你可以像这样创建多行字符串。
''';
var s2 = """这也是一个多行字符串。""";
}
2.3.2 Number
Dart 语言的 Number 有两种类型:
- int
整数值不大于64位, 具体取决于平台。 在 Dart VM 上, 值的范围从 -263 到 263 - 1. Dart 被编译为 JavaScript 时,使用 JavaScript numbers, 值的范围从 -253 到 253 - 1.
- double
64位(双精度)浮点数,依据 IEEE 754 标准。
int 和 double 都是 num. 的亚类型。 num 类型包括基本运算 +, -, /, 和 *, 以及 abs(), ceil(), 和 floor(), 等函数方法。 (按位运算符,例如»,定义在 int 类中。) 如果 num 及其亚类型找不到你想要的方法, 尝试查找使用 dart:math 库。
// int数字形式
int age = 20;
print(age);
// double数字形式
double age2 = 20.5;
print(age2);
2.3.3 Boolean
Dart 使用 bool 类型表示布尔值。 Dart 只有字面量 true and false 是布尔类型, 这两个对象都是编译时常量。
Dart 的类型安全意味着不能使用 if (nonbooleanValue) 或者 assert (nonbooleanValue)。
// bool形式
bool isTrue = true;
print(isTrue);
if (isTrue) {
print("真");
}
2.3.4 List
- 几乎每种编程语言中最常见的集合可能是 array 或有序的对象集合。 在 Dart 中的 Array 就是 List 对象, 通常称之为 List 。Dart 中的 List 字面量非常像 JavaScript 中的 array 字面量。
- Dart 在 2.3 引入了 扩展操作符(…)和 空感知扩展操作符(…?),它们提供了一种将多个元素插入集合的简洁方法。
// 集合
var l1 = ["shu", "shu", 2];
for (var i in l1) {
print(i);
}
// 指定类型
var l2 = <int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (var i in l2) {
print(i);
}
var l3 = List.filled(3, "shu");
for (var i in l3) {
print(i);
}
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
2.3.5 Map
通常来说, Map 是用来关联 keys 和 values 的对象。 keys 和 values 可以是任何类型的对象。在一个 Map 对象中一个 key 只能出现一次。 但是 value 可以出现多次。 Dart 中 Map 通过 Map 字面量 和 Map 类型来实现。
// 定义Map
var m1 = {
"name": "shu",
"age": 20,
"isTrue": true,
"l1": ["shu", "shu", 2]
};
print(m1["name"]);
print(m1["age"]);
print(m1["isTrue"]);
print(m1["l1"]);
print("################################################################");
// 定义Map
var m2 = Map<String, dynamic>();
m2["name"] = "shu";
m2["age"] = 20;
m2["isTrue"] = true;
m2["l1"] = ["shu", "shu", 2];
print(m2["name"]);
print(m2["age"]);
print(m2["isTrue"]);
print(m2["l1"]);
print("################################################################");
// 定义Map
var m3 = Map<String, dynamic>();
m3["name"] = "shu";
m3["age"] = 20;
m3["isTrue"] = true;
m3["l1"] = ["shu", "shu", 2];
print(m3["name"]);
print(m3["age"]);
print(m3["isTrue"]);
print(m3["l1"]);
print("################################################################");
// 定义Map
var m4 = Map<String, dynamic>();
m4["name"] = "shu";
m4["age"] = 20;
m4["isTrue"] = true;
m4["l1"] = ["shu", "shu", 2];
print(m4["name"]);
print(m4["age"]);
print(m4["isTrue"]);
print(m4["l1"]);
print("################################################################");
var m5 = new Map();
m5["name"] = "shu";
m5["age"] = 20;
m5["isTrue"] = true;
m5["l1"] = ["shu", "shu", 2];
print(m5["name"]);
print(m5["age"]);
print(m5["isTrue"]);
print(m5["l1"]);
2.3.6 Set集合
- 在 Dart 中,set 是一组特定元素的无序集合。 Dart 支持的集合由集合的字面量和 Set 类提供。
- 尽管 Set 类型(type) 一直都是 Dart 的一项核心功能,但是 Set 字面量(literals) 是在 Dart 2.2 中才加入的。
- 从 Dart 2.3 开始,Set 可以像 List 一样支持使用扩展操作符(… 和 …?)以及 Collection if 和 for 操作。你可以查阅 List 扩展操作符 和 List 集合操作符 获取更多相关信息。
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
2.3.7 完整代码
/*
* @Description:数据类型.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-29 19:28:36
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-29 20:50:31
*/
void main(List<String> args) {
// 字符串形式
String name = 'shu';
print(name);
// 字符串形式
var name2 = 'shu';
print(name2);
// 字符串的拼接
var name3 = 'shu' + 'shu';
print(name3);
// ${expression}
var s = 'string interpolation';
print('${s}');
// 字符串截取
print(s.substring(2));
// 应该说字符串的常用方法,都基本拥有
print("##############################################################");
// int数字形式
int age = 20;
print(age);
// double数字形式
double age2 = 20.5;
print(age2);
print("##############################################################");
// bool形式
bool isTrue = true;
print(isTrue);
if (isTrue) {
print("真");
}
print("################################################################");
// 集合
var l1 = ["shu", "shu", 2];
for (var i in l1) {
print(i);
}
// 指定类型
var l2 = <int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (var i in l2) {
print(i);
}
var l3 = List.filled(3, "shu");
for (var i in l3) {
print(i);
}
print("################################################################");
// 定义Map
var m1 = {
"name": "shu",
"age": 20,
"isTrue": true,
"l1": ["shu", "shu", 2]
};
print(m1["name"]);
print(m1["age"]);
print(m1["isTrue"]);
print(m1["l1"]);
print("################################################################");
// 定义Map
var m2 = Map<String, dynamic>();
m2["name"] = "shu";
m2["age"] = 20;
m2["isTrue"] = true;
m2["l1"] = ["shu", "shu", 2];
print(m2["name"]);
print(m2["age"]);
print(m2["isTrue"]);
print(m2["l1"]);
print("################################################################");
// 定义Map
var m3 = Map<String, dynamic>();
m3["name"] = "shu";
m3["age"] = 20;
m3["isTrue"] = true;
m3["l1"] = ["shu", "shu", 2];
print(m3["name"]);
print(m3["age"]);
print(m3["isTrue"]);
print(m3["l1"]);
print("################################################################");
// 定义Map
var m4 = Map<String, dynamic>();
m4["name"] = "shu";
m4["age"] = 20;
m4["isTrue"] = true;
m4["l1"] = ["shu", "shu", 2];
print(m4["name"]);
print(m4["age"]);
print(m4["isTrue"]);
print(m4["l1"]);
print("################################################################");
var m5 = new Map();
m5["name"] = "shu";
m5["age"] = 20;
m5["isTrue"] = true;
m5["l1"] = ["shu", "shu", 2];
print(m5["name"]);
print(m5["age"]);
print(m5["isTrue"]);
print(m5["l1"]);
print("################################################################");
// 类型判断
print(m5 is Map<String, dynamic>);
}
2.4 运算符
2.4.1 算术运算符
Operator | Meaning |
---|---|
+ | Add |
– | Subtract |
-expr | Unary minus, also known as negation (reverse the sign of the expression) |
* | Multiply |
/ | Divide |
~/ | Divide, returning an integer result |
% | Get the remainder of an integer division (modulo) |
// 算术运算符
var a = 10;
var b = 3;
print(a + b);
print(a - b);
print(a * b);
print(a / b);
print(a % b);
print(a ~/ b);
2.4.2 关系运算符
Operator | Meaning |
---|---|
== | Equal; see discussion below |
!= | Not equal |
> | Greater than |
< | Less than |
>= | Greater than or equal to |
<= | Less than or equal to |
// 关系运算符
print(a == b);
print(a != b);
print(a > b);
print(a < b);
print(a >= b);
print(a <= b);
2.4.3 逻辑运算符
Operator | Meaning |
---|---|
!expr | inverts the following expression (changes false to true, and vice versa) |
|| | logical OR |
&& | logical AND |
var c = true;
var d = false;
print(c && d);
print(c || d);
print(!c);
2.4.4 赋值运算符
= | –= | /= | %= | >>= | ^= |
---|---|---|---|---|---|
+= | *= | ~/= | <<= | &= | |= |
var e = 10;
e += 3;
print(e);
e -= 3;
print(e);
e *= 3;
print(e);
e %= 3;
print(e);
e ~/= 3;
print(e);
2.4.5 位移运算符
Operator | Meaning |
---|---|
& | AND |
| | OR |
^ | XOR |
~expr | Unary bitwise complement (0s become 1s; 1s become 0s) |
<< | Shift left |
>> | Shift right |
// 位运算符
var f = 10;
var g = 3;
print(f & g);
print(f | g);
print(f ^ g);
print(f << g);
print(f >> g);
2.4.6 类型判定运算符
as, is, 和 is! 运算符用于在运行时处理类型检查。
Operator | Meaning |
---|---|
as | Typecast (也被用于指定库前缀) |
is | True if the object has the specified type |
is! | False if the object has the specified type |
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
2.4.7 三目运算符
Dart有两个运算符,有时可以替换 if-else 表达式, 让表达式更简洁:
condition ? expr1 : expr2
如果条件为 true, 执行 expr1 (并返回它的值): 否则, 执行并返回 expr2 的值。
expr1 ?? expr2
如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。
// 三目运算符
var d = a > b ? a : b;
print(d);
2.4.8 级联运算符
级联运算符 (…) 可以实现对同一个对像进行一系列的操作。 除了调用函数, 还可以访问同一对象上的字段属性。 这通常可以节省创建临时变量的步骤, 同时编写出更流畅的代码。
querySelector('#confirm') // 获取对象。
..text = 'Confirm' // 调用成员变量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
// 等价于
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
2.5 流程操作语句
2.5.1 if-else
- Dart 支持 if - else 语句,其中 else 是可选的
- 和 JavaScript 不同, Dart 的判断条件必须是布尔值,不能是其他类型。
// if 条件表达式
var a = 10;
var b = 3;
if (a > b) {
print("a大于b");
} else if (a < b) {
print("a小于b");
} else {
print("a等于b");
}
2.5.2 for循环
进行迭代操作,可以使用标准 for 语句。
// 循环语句
for (var i = 0; i < 10; i++) {
print(i);
}
2.5.3 While与Do-While
- while 循环在执行前判断执行条件
- do-while 循环在执行后判断执行条件
// while循环
var e = 0;
while (e < 10) {
print(e);
e++;
}
// do-while循环
var f = 0;
do {
print(f);
f++;
} while (f < 10);
2.5.4 Swith与Case
在 Dart 中 switch 语句使用 == 比较整数,字符串,或者编译时常量。 比较的对象必须都是同一个类的实例(并且不可以是子类), 类必须没有对 == 重写。 枚举类型 可以用于 switch 语句。
// switch 条件表达式
var c = 'shu';
switch (c) {
case 'shu':
print("shu");
break;
case 'shu2':
print("shu2");
break;
default:
print("default");
}
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
2.5.5 Assert
- 如果 assert 语句中的布尔条件为 false , 那么正常的程序执行流程会被中断。
- 提示: assert 语句只在开发环境中有效, 在生产环境是无效的; Flutter 中的 assert 只在 debug 模式 中有效。 开发用的工具,例如 dartdevc 默认是开启 assert 功能。 其他的一些工具, 例如 dart 和 dart2js,支持通过命令行开启 assert : --enable-asserts。
- assert 的第二个参数可以为其添加一个字符串消息。
// 确认变量值不为空。
assert(text != null);
// 确认变量值小于100。
assert(number < 100);
// 确认 URL 是否是 https 类型。
assert(urlString.startsWith('https'));
2.6 函数
- 任何应用都必须有一个顶级 main() 函数,作为应用服务的入口。 main() 函数返回值为空,参数为一个可选的 List 。
- 多数函数是有名字的, 比如 main() 和 printElement()。 也可以创建没有名字的函数,这种函数被称为 匿名函数, 有时候也被称为 lambda 或者 closure 。 匿名函数可以赋值到一个变量中, 举个例子,在一个集合中可以添加或者删除一个匿名函数。
- 可选参数可以是命名参数或者位置参数,但一个参数只能选择其中一种方式修饰。
/*
* @Description:函数
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 13:43:12
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-30 14:13:58
*/
void main(List<String> args) {
// 内置方法
print('hello world');
// 普通定义方法
int sum(int a, int b) {
return a + b;
}
print(sum(1, 2));
// 可选参数
void getUserInfo(String name, [int? age]) {
print('name:$name,id:$age');
}
getUserInfo('shu');
// 带有默认参数
void getUserInfo2(String name, [int age = 18]) {
print('name:$name,id:$age');
}
getUserInfo2('shu');
getUserInfo2('shu', 20);
// 定义一个命名参数
void getUserInfo3(String name, {int age = 18}) {
print('name:$name,id:$age');
}
getUserInfo3('shu', age: 20);
// 匿名方法
var sum2 = (int a, int b) {
return a + b;
};
print(sum2(1, 2));
}
/*
* @Description: 箭头函数
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 14:16:24
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-30 14:17:27
*/
void main(List<String> args) {
// 箭头函数
var sum = (int a, int b) => a + b;
print(sum(1, 2));
// for循环中的箭头函数
List list=[1,2,3,4,5];
list.forEach((item)=>print(item));
}
/*
* @Description:匿名方法
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 14:25:28
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-30 14:30:04
*/
void main(List<String> args) {
// 匿名方法
var sum = (int a, int b) {
return a + b;
};
print(sum(1, 2));
// 自执行方法
(() {
print('hello world');
})();
// 方法的递归
void sum2(int a, int b) {
if (a > b) {
sum2(a - b, b);
} else {
print(a);
}
}
sum2(10, 5);
}
2.7 异常
Dart 代码可以抛出和捕获异常。异常表示一些未知的错误情况,如果异常没有捕获则会被抛出从而导致抛出异常的代码终止执行。
与 Java 不同的是,Dart 的所有异常都是非必检异常,方法不必声明会抛出哪些异常,并且你也不必捕获任何异常。
Dart 提供了 Exception 和 Error 两种类型的异常以及它们一系列的子类,你也可以定义自己的异常类型。但是在 Dart 中可以将任何非 null 对象作为异常抛出而不局限于 Exception 或 Error 类型。
/*
* @Description:异常.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 20:34:17
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-30 20:34:18
*/
void main(List<String> args) {
// try catch finally
try {
throw 'error';
} catch (e) {
print(e);
} finally {
print('finally');
}
}
三 高级内容
3.1 类与对象
Dart 是一种基于类和 mixin 继承机制的面向对象的语言。 每个对象都是一个类的实例,所有的类都继承于 Object. 。 基于 * Mixin 继承* 意味着每个类(除 Object 外) 都只有一个超类, 一个类中的代码可以在其他多个继承类中重复使用。
3.1.1 申明类
- 对象的 成员 由函数和数据(即 方法 和 实例变量)组成。方法的 调用 要通过对象来完成,这种方式可以访问对象的函数和数据。
/*
* @Description: 类与对象.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 19:38:00
* @LastEditors: 修改者填写
* @LastEditTime: 2022-07-30 22:01:45
*/
// Dart中定义一个类
class Person {
String? name;
int? age;
// 构造方法
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 实例方法
void sayHello() {
print('Hello, I am $name, $age years old.');
}
}
3.1.2 构造函数
- 使用(.)来访问对象的实例变量或方法
- 使用 ?. 代替 . 可以避免因为左边表达式为 null 而导致的问题
- 可以使用 构造函数 来创建一个对象。构造函数的命名方式可以为 类名 或 _类名 . 标识符 _的形式。
- 可以使用 Object 对象的 runtimeType 属性在运行时获取一个对象的类型,该对象类型是 Type 的实例。
- 如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的构造函数并且该构造函数会调用其父类的无参数构造方法。
- 子类不会继承父类的构造函数,如果子类没有声明构造函数,那么只会有一个默认无参数的构造函数。
var p = Point(2, 2);
// Get the value of y.
assert(p.y == 2);
// Invoke distanceTo() on p.
double distance = p.distanceTo(Point(4, 4));
// If p is non-null, set a variable equal to its y value.
var a = p?.y;
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
print('The type of a is ${a.runtimeType}');
3.1.3 实例变量
所有实例变量均会隐式地声明一个 Getter 方法。非终值的实例变量和 late final 声明但未声明初始化的实例变量还会隐式地声明一个 Setter 方法。
String? name;
int? age;
3.1.4 终值初始化
- 对于大多数编程语言来说在构造函数中为实例变量赋值的过程都是类似的,而 Dart 则提供了一种特殊的语法糖来简化该步骤。
- 构造中初始化的参数可以用于初始化非空或 final 修饰的变量,它们都必须被初始化或提供一个默认值。
class Point {
final double x;
final double y;
// Sets the x and y instance variables
// before the constructor body runs.
Point(this.x, this.y);
}
3.1.5 超类参数
为了不重复地将参数传递到超类构造的指定参数,你可以使用超类参数,直接在子类的构造中使用超类构造的某个参数。超类参数不能和重定向的参数一起使用。(就是调用父类的成员变量)
class Vector2d {
final double x;
final double y;
Vector2d(this.x, this.y);
}
class Vector3d extends Vector2d {
final double z;
// Forward the x and y parameters to the default super constructor like:
// Vector3d(final double x, final double y, this.z) : super(x, y);
Vector3d(super.x, super.y, this.z);
}
3.1.6 命名构造方法
Dart类中两个同名构造方法不能重载,但是Dart语言为类新增了一种称为命名构造方法的东西。
/*
* @Description: 类与对象.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-07-30 19:38:00
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 09:19:33
*/
// Dart中定义一个类
class Person {
String? name;
int? age;
// 构造方法A
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 命名构造方法
Person.fromData(Map data) {
this.name = data['name'];
this.age = data['age'];
}
}
3.1.7 常量构造方法
如果想提供一个状态永远不变的对像,在Dart中,我们可以创建一个编译时常量对象,节省开销。
// 常量构造方法,如果想提供一个状态永远不变的对像,在Dart中,我们可以创建一个编译时常量对象,节省开销。
static final Person? _singleton = Person("a", 19);
// 常量构造方法
print(Person._singleton?.getName());
print(Person._singleton?.age);
3.1.8 工厂构造方法
使用 factory 关键字标识类的构造函数将会令该构造函数变为工厂构造函数,这将意味着使用该构造函数构造类的实例时并非总是会返回新的实例对象。例如,工厂构造函数可能会从缓存中返回一个实例,或者返回一个子类型的实例。
/*
* @Description:工厂构造方法.dart
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 09:35:37
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 09:47:31
*/
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
var logger = Logger('UI');
logger.log('Button clicked');
var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);
}
3.2 抽象类
- 使用关键字 abstract 标识类可以让该类成为 抽象类,抽象类将无法被实例化。抽象类常用于声明接口方法、有时也会有具体的方法实现。如果想让抽象类同时可被实例化,可以为其定义 工厂构造函数。
- 实例方法、Getter 方法以及 Setter 方法都可以是抽象的,定义一个接口方法而不去做具体的实现让实现它的类去实现该方法,抽象方法只能存在于 抽象类中。
- 直接使用分号(;)替代方法体即可声明一个抽象方法:
- 使用 extends 关键字来创建一个子类,并可使用 super 关键字引用一个父类
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 12:21:01
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:10:07
*/
// 定义一个抽象方法
abstract class action {
void run();
void left();
void right(){
print('right');
}
}
// 实现抽象方法
class runs extends action {
@override
void left() {
// TODO: implement left
}
@override
void run() {
// TODO: implement run
}
// 利用super调用父类的方法 如果没有super 则不能调用父类的方法
void right() {
super.right();
}
}
3.3 接口
每一个类都隐式地定义了一个接口并实现了该接口,这个接口包含所有这个类的实例成员以及这个类所实现的其它接口。如果想要创建一个 A 类支持调用 B 类的 API 且不想继承 B 类,则可以实现 B 类的接口。
/*
* @Description:接口
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:08:25
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:08:25
*/
// 定义一个接口
class Person {
// In the interface, but visible only in this library.
final String _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// 实现接口
class Impostor implements Person {
String get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
3.4 枚举类型
- 枚举类型是一种特殊的类型,也称为 enumerations 或 enums,用于定义一些固定数量的常量值。
- 所有的枚举都继承于 Enum 类。枚举类是封闭的,即不能被继承、被实现、被 mixin 混入或显式被实例化。
- 抽象类和 mixin 可以显式的实现或继承 Enum,但只有枚举可以实现或混入这个类,其他类无法享有同样的操作。
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:14:06
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:14:06
*/
// 定义一个枚举类
enum Color {
red,
green,
blue,
}
// 使用枚举类
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}
3.5 类变量与方法
- 使用关键字 static 可以声明类变量或类方法。
- 静态变量(即类变量)常用于声明类范围内所属的状态变量和常量
- 静态变量在其首次被使用的时候才被初始化。
- 静态方法(即类方法)不能对实例进行操作,因此不能使用 this。但是他们可以访问静态变量。
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:19:50
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:19:51
*/
class Queue {
// 定义一个类变量
static const initialCapacity = 16;
}
void main() {
assert(Queue.initialCapacity == 16);
}
// 类方法可以直接通过类名直接调用
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
3.6 泛型
- 如果你查看数组的 API 文档,你会发现数组 List 的实际类型为 List。 <…> 符号表示数组是一个 泛型(或 参数化类型) 通常 使用一个字母来代表类型参数,比如 E、T、S、K 和 V 等等。
- 适当地指定泛型可以更好地帮助代码生成。
- 使用泛型可以减少代码重复。
- 与 Java 不同的是,Java 中的泛型是类型 擦除 的,这意味着泛型类型会在运行时被移除。在 Java 中你可以判断对象是否为 List 但不可以判断对象是否为 List。
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:25:07
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:27:17
*/
void main(List<String> args) {
// 定义一个泛型数据类型
var arr = <String>[];
// 由于我们制定了泛型为String,所以我们只能添加String类型的数据
arr.add('1');
arr.add('2');
arr.add('3');
arr.add('4');
}
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:25:07
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:29:33
*/
void main(List<String> args) {
// 定义一个泛型数据类型
var arr = <String>[];
// 由于我们制定了泛型为String,所以我们只能添加String类型的数据
arr.add('1');
arr.add('2');
arr.add('3');
arr.add('4');
var arr2 = [];
// 定义一个泛型方法,我们这里定义一个泛型方法,没有指定泛型方法,因此可以随意添加数据类型
void add<T>(T t) {
arr2.add(t);
}
}
有时使用泛型的时候,你可能会想限制可作为参数的泛型范围,也就是参数必须是指定类型的子类,这时候可以使用 extends 关键字。
// 当然我们也可以定义一个泛型类,比如:String
class Foo<T extends String> {
// Any type provided to Foo for T must be non-nullable.
}
3.7 库的导入
- import 和 library 关键字可以帮助你创建一个模块化和可共享的代码库。代码库不仅只是提供 API 而且还起到了封装的作用:以下划线(_)开头的成员仅在代码库中可见。 每个 Dart 程序都是一个库,即便没有使用关键字 library 指定。
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:35:51
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:35:51
*/
import 'dart:math';
void main(List<String> args) {
// 随机数
var random = new Random();
print(random.nextInt(100));
}
- import 的唯一参数是用于指定代码库的 URI,对于 Dart 内置的库,使用 dart:xxxxxx 的形式。而对于其它的库,你可以使用一个文件系统路径或者以 package:xxxxxx 的形式。
import 'package:test/test.dart';
- 如果你导入的两个代码库有冲突的标识符,你可以为其中一个指定前缀。
import 'package:lib1/lib1.dart';
// 利用as来指定前缀
import 'package:lib2/lib2.dart' as lib2;
- 如果你只想使用代码库中的一部分,你可以有选择地导入代码库。
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
延迟加载(也常称为 懒加载)允许应用在需要时再去加载代码库,下面是可能使用到延迟加载的场景:
- 为了减少应用的初始化时间。
- 处理 A/B 测试,比如测试各种算法的不同实现。
- 加载很少会使用到的功能,比如可选的屏幕和对话框。
- 使用 deferred as 关键字来标识需要延时加载的代码库
import 'package:greetings/hello.dart' deferred as hello;
3.8 异步支持
- Dart 代码库中有大量返回 Future 或 Stream 对象的函数,这些函数都是 异步 的,它们会在耗时操作(比如I/O)执行完毕前直接返回而不会等待耗时操作执行完毕。
- async 和 await 关键字用于实现异步编程,并且让你的代码看起来就像是同步的一样。
- 使用 async 和 await 的代码是异步的,但是看起来有点像同步代码。
- 必须在带有 async 关键字的 异步函数 中使用 await。
- await 表达式的返回值通常是一个 Future 对象;如果不是的话也会自动将其包裹在一个 Future 对象里。 Future 对象代表一个“承诺”, await 表达式会阻塞直到需要的对象返回。
/*
* @Description:
* @version: 1.0
* @Author: shu
* @Date: 2022-08-01 13:46:32
* @LastEditors: 修改者填写
* @LastEditTime: 2022-08-01 13:56:32
*/
Future<void> checkVersion() async {
try {
var version = await lookUpVersion();
print(version);
} catch (e) {
print(e);
}
}
// 定义一个方法,返回一个Future对象
lookUpVersion() {
return Future.delayed(Duration(seconds: 1), () => '1.0.0');
}
void main(List<String> args) {
checkVersion();
}
更多知识参考官方网站:https://dart.cn/guides/language/language-tour#abstract-classes
边栏推荐
- Upload markdown documents to blog garden
- 2022-08-01 第八组 曹雨 泛型 枚举
- 迁移学习——Discriminative Transfer Subspace Learning via Low-Rank and Sparse Representation
- VGUgarbage collector(垃圾回收器)的实现原理
- Implementation principle of VGUgarbage collector (garbage collector)
- number of solutions to solve a multivariate multi-degree equation
- 自建 Prometheus 采集腾讯云容器服务监控数据最佳实践
- Flink cluster construction
- dvwa 通关记录1 - 暴力破解 Brute Force
- Analysis of the development trend of game metaverse
猜你喜欢
使用分类权重解决数据不平衡的问题
今年的很美味
How to prevent governance attacks in DAOs?
Small program -- subcontracting
FusionGAN:A generative adversarial network for infrared and visible image fusion文章学习笔记
SOM Network 1: Principles Explained
基于php在线音乐网站管理系统获取(php毕业设计)
[ASM] Bytecode Operation MethodWriter
游戏元宇宙发展趋势展望分析
威纶通触摸屏如何打开并升级EB8000旧版本项目并更换触摸屏型号?
随机推荐
基于php影视资讯网站管理系统获取(php毕业设计)
迁移学习——Discriminative Transfer Subspace Learning via Low-Rank and Sparse Representation
Today's sleep quality record 74 points
WEB渗透之SQL 注入
ModuleNotFoundError: No module named ‘yaml‘
今年的很美味
selenium无头,防检测
基于php在线学习平台管理系统获取(php毕业设计)
dvwa 通关记录1 - 暴力破解 Brute Force
小程序中的多表联合查询
shell编程规范与变量
ARFoundation Getting Started Tutorial U2-AR Scene Screenshot Screenshot
高等代数_证明_矩阵的任意特征值的代数重数大于等于其几何重数
MySQL related knowledge
论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》
入门数据库Days4
基于php动漫周边商城管理系统(php毕业设计)
Based on php online examination management system acquisition (php graduation design)
ImportError: `save_weights` requires h5py.问题解决
ImportError: `save_weights` requires h5py. Problem solved