dart

重要概念

任何保存在变量中的都是一个对象, 所有对象继承自 Object 类

Dart是强类型的,但是Dart可以推断类型,number被推断为int类型。如果明确不需要任何类型,需要使用特殊类型 dynamic

Dart支持泛型,如List 整数列表 或 List (任何类型的对象列表)

Dart 如果标识符以下划线(_)开头,则它相对于库是私有的

内建类型

在声明变量时,未显示指定类型,默认是dynamic

var const final 在声明时, 指定类型方式不同

1
2
3
4
5
const int a = 3;       // 可以
final String b = '4'; // 可以

var String c = '5'; // 报错
String d = '6'; // 可以

Number

声明方式

1
2
3
4
5
var aa = 3;

// 显示声明类型
int aa = 3;
double aa = 3;

如果num及亚类型找不到你想要的方法, 尝试dart:math库

1
2
3
Number  
|-int
|-double 64位(双精度)浮点数
  • var one = int.parse('1');

  • var onePointOne = double.parse('1.1');

  • String oneAsString = 1.toString();

  • String piAsString = 3.14159.toStringAsFixed(2);

String

声明方式

1
2
3
4
var a = 'string';

// 显示声明类型方式
String a = 'string';

支持 ${expression}内嵌表达式, 变量可省略{}符号

1
2
3
var s = 'string interpolation';
print('Dart has $s');
print('Dart has ${s}');

连续三个单引号或者三个双引号实现多行

1
2
3
4
5
6
7
8
9
var s1 = '''
one
two
''';

var s2 = """
one
two
""";

Boolean

声明方式

1
2
3
var aab = true;
// 显示声明类型方式
bool aa = true;

只有字面量 true,false是布尔类型

1
2
3
4
5
6
7
8
9
10
11
// 检查空字符串
var fullName = ''; assert(fullName.isEmpty);

// 检查 0 值。
var hitPoints = 0; assert(hitPoints <= 0);

// 检查 null 值。
var unicorn; assert(unicorn == null);

// 检查 NaN 。
var iMeantToDoThis = 0 / 0; assert(iMeantToDoThis.isNaN);

List

如果想创建一个固定不变的 list 或者其他自定义集合类型,这种情况下你需要使用构造函数。通常在 Dart 代码中并不使用构造函数

声明方式

  • 字面量: var list = []

  • 构造函数: var list = List()

指定类型

  • 字面量: var list = <int>[]

  • 构造函数: var list = List<int>()

  • List<int> aa = [1];

1
2
// Dart 推断list的类型为List<int> 。 将非整数对象添加到此List中,会引发错误
var list = [1, 2, 3];

Set

一个元素唯一且无序的集合

声明方式

1
2
3
4
5
6
7
8
9
// 这样会创建一个Map,而不是Set
var names = {};

// 这样会创建一个Set
var names = {'n', 'm'};

// 显示声明类型方式
var names = <String>{};
Set<String> names = {};

先有的Map字面量语法,所以 {} 默认是 Map 类型。忘记在 {} 上注释类型或赋值到一个未声明类型的变量上,那么 Dart 会创建一个类型为 Map<dynamic, dynamic> 的对象。

Map

声明方式

  • var aa = {};

显示类型

1
2
3
var gifts = <String, String>{ 'first': 'partridge' };

Map<String, String> name = { 'first': 'partridge' };
  • var aa = Map();

  • LinkedHashMap();

Map 是用来关联 keys 和 values 的对象。keys 和 values 可以是任何类型的对象

Rune (表示Unicode字符)

Rune 用来表示字符串中的 UTF-32 编码字符。

Symbol

一个 Symbol 对象表示 Dart 程序中声明的运算符或者标识符

变量

var

  1. var 声明的变量,初始值要是 null 的话,后面给什么值都可以

  2. 只要 var 的变量给初始值明确类型,(自动推断类型),后面赋值只能是该类型

1
2
3
4
5
6
7
8
9
10
11
12
var name;
void test() {
name = 11;
name = "AA";
}

// 这样报错
var name = 10;
void test() {
name = 11;
name = "AA";
}

变量仅存储对象引用,这里的变量是 name 存储了一个 String 类型的对象引用

1
var name = 'Bob';

未初始化的变量默认值是 null,即变是数值类型

1
2
int lineCount;
assert(lineCount == null);

使用字面量

List和map字面量可以被参数化。参数化字面量仅仅是在字面量的开始括号之前添加(对于list类型)或者添加<keyType, valueType>(对于map类型)

final 和 const

Final 有个getter但是没有setter,必须在声明时就初始化,用它标记的变量可以在运行时确定

声明方式

1
2
final name = 'Bob';
final String nickname = 'Bobby';

不可修改

1
2
final name = 'Bob';
name = 'Alice'; // Error: 一个 final 变量只能被设置一次。

在运行时声明一个不可变的引用,这个引用一旦确定就不可再变

1
2
3
4
var x = 100;          // 运行时变量,可以是任意其他值
var y = 30; // 运行时变量,可以是任意其他值

final res = x / y;

编译时就固定变量的值,可使用const

1
const bar = 1000000;

const可以用来创建常量值,以及声明创建常量值的构造函数

1
2
var foo = const [];
final bar = const [];

函数

推荐指定函数类型

1
2
3
4
5
6
7
8
// bool 返回类型   参数int类型
bool isNoble(int atomicNumber) {
return something != null;
}

// 支持箭头函数

bool isNoble(int atomicNumber) => something != null;

必填参数

@required 注释表示参数是 required 性质的命名参数。Required 被定义在 meta package中.

1
const Scrollbar({Key key, @required Widget child})

位置可选参数

1
2
3
4
5
6
7
String hello(String world, [String device]) {
var result = '$world';
if (device != null) {
result = '$device';
}
return result;
}

main() 函数

任何应用都必须有一个顶级 main() 函数,作为入口, 返回值为空,参数为一个可选的 List<String>

运算符

??=

只有当被赋值的变量为 null 时才会赋值给它。

1
b ??= value;

expr1 ?? expr2

如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。

1
2
3
如果赋值是基于判定是否为 null, 考虑使用 ??。

String playerName(String name) => name ?? 'Guest';

级联运算符(..)

级联运算符 (..) 可以实现对同一个对像进行一系列的操作,可以嵌套。 可以调用函数, 访问同一对象上的字段属性等。 通常可以节省创建临时变量的步骤

1
2
3
4
querySelector('#confirm')      // 获取对象。
..text = 'Confirm' // 调用成员变量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

?.

可以避免因为左边对象可能为 null , 导致的异常

1
2
// 如果 p 为 non-null,设置它变量 y 的值为 4。
p?.y = 4;

继承

extends 关键字来创建子类, 使用 super 关键字来引用父类

1
2
3
4
5
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
}
}

重写类

可以使用 @override 注解指出想要重写

1
2
3
4
5
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}

Dart 导库方式

1
2
3
4
5
6
7
8
9
10
11
// 标准库 如: dart:io、dart:html、dart:math

import 'dart:io';

// Pub包管理器,使用前缀 package:

import 'package:flutter/material.dart';

// 指定路径,可以是相对路径或绝对路径

import 'lib/student/student.dart';

特殊

  • == 运算符用来测试两个对象是否相等

实例变量

所有实例变量都生成隐式 getter 方法。 非 final 的实例变量同样会生成隐式 setter 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
var point = Point();
print(point.x);
print(point.y);
print(point.m);
print(point.n);
}
class Point {
num x = 1;
num y = 3;
var m = 4;
final n = 8;
}

通过构造函数创建对象

  • 通过创建一个与其类同名的函数来声明构造函数, 生成构造函数, 创建一个类的实例

  • 在没有声明构造函数的情况下, Dart会提供一个默认的构造函数, 没有参数并会调用父类的无参构造函数

  • 关键字 this 是指当前的,只有在命名冲突时有效,否则dart会忽略处理

  • 通常模式下,会将构造函数传入的参数的值赋值给对应的实例变量

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
var point = Point(1, 5);
print(point.x);
print(point.y);
}

class Point {
num x, y;
Point(num x, num y) {
this.x = x;
this.y = y;
}
}

命名构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
void main() {
var name = HasNameClass.setNme({'x': 1, 'y': 4});
print(name.x);
print(name.y);
}
class HasNameClass {
int x,y;
HasNameClass();
HasNameClass.setNme(Map param) {
x = param['x'];
y = param['y'];
}
}

关于继承时构造函数

特别研读

  • 子类不能继承父类的构造函数,这意味着父类的命名构造函数不会被子类继承

  • 如果希望使用父类中定义的命名构造函数创建子类,就必须在子类中实现该构造函数

  • 默认情况下,子类的构造函数会自动调用父类的默认构造函数(匿名,无参数)

  • 如果父类中没有匿名无参的构造函数, 则需要手动调用父类的其他构造函数。 在当前构造函数冒号 (:) 之后,函数体之前,声明调用父类构造函数

无需参数, 也无需显示调用构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main() {
var emp = new Employee();
print(emp.parent());
print(emp.parentStr);
print(emp.sub);
}
class Person {
String parentStr = '333';
int parent() {
return 1;
}
}
class Employee extends Person {
var sub = 3;
}

父子各用各的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void main() {
var emp = new Employee({});
print(emp.parent());
print(emp.parentStr);
print(emp.sub);
}
class Person {
String parentStr = '333';
Person();
int parent() {
return 1;
}
}
class Employee extends Person {
var sub = 3;
Employee(Map json);
}

如果父类是命名构造函数,父类中没有匿名无参的构造函数,则需要手工调用父类的其他构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void main() {
var emp = new Employee({});
print(emp.parent());
print(emp.parentStr);
print(emp.sub);
}
class Person {
String parentStr = '333';

Person.fromJson(Map data) {
print('in Person');
}

int parent() {
return 1;
}
}
class Employee extends Person {
var sub = 3;
Employee(Map data) : super.fromJson(data) {
print('in Employee');
}
}

初始化列表除了调用超类构造函数之外,还可以在构造函数体执行之前初始化实例变量。各参数的初始化用逗号分隔。

1
2
3
4
5
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}

工厂构造函数

  • 类包含:属性、方法和构造函数,其中构造函数包含类名构造函数命名构造方法,在构造方法前加上factory之后变成了工厂构造函数

  • 工厂构造函数不能和其他构造函数一样,使用this关键字来使用class的属性和方法

  • 工厂构造函数只能使用类中static类型的属性和方法,不能使用非静态的属性或者方法

  • 非工厂类中的构造函数可以使用this.的方式调用类中的非静态属性或者方法,int xxx; this.xxx=xx

  • 不论工厂构造函数还是非工厂构造函数,都可以使用静态(static)类型的属性和方法,static int b; b=xx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Logger {
final String name;
bool mute = false;

// 从命名的 _ 可以知,
// _cache 是私有属性。
static final Map<String, Logger> _cache =
<String, Logger>{};

factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}

抽象类

  • 使用 abstract 修饰符来定义 抽象类 — 抽象类不能实例化

  • 抽象类通常用来定义接口,以及部分实现

  • 如果希望抽象类能够被实例化,那么可以通过定义一个 工厂构造函数 来实现

1
2
3
abstract class AbstractContainer {
void updateChildren();
}

接口实现

  • Dart没有声明接口的语法。每个类都隐式的定义了一个接口,接口包含了该类所有的实例成员及其实现的接口

  • 实现多个接口用逗号分隔

  • 接口是数据结构的约定, 如果接口定义了三个参数, 但是在实现时只有两个, 则会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void main() {
InterPerson cp = new InterPerson();
cp.getname(); // InterPerson
cp.init(); // InterPersonInit
print(cp.height); // 10
}

// 普通类, 每个类(包括抽象类)都隐式的定义了一个接口
class Person {
final int height = 10;
void getname() {
print("Person");
}
}

// 抽象类通常用来定义接口,以及部分实现, 抽象类不可以实例化
abstract class OtherPerson {
void init() {
print("OtherPerson");
}
}

class InterPerson implements Person, OtherPerson {
final int height = 10;
void getname() {
print("InterPerson");
}
void init() {
print("InterPersonInit");
}
}
返回
顶部