变量
声明变量几种方式:
1. var name = "Tim"; //自动推倒类型(infer)为string
2. String name = "Tim"; //强类型定义
3. dynamic name = "Tim"; //可以修改变量类型 name = 4.0;
4. final name = "Tim"; //首次使用时执行一次
5. const name = "Tim"; //类似全局常量或者static,编译期间确定值
如果没有赋初始值,默认变量初始值为null。
内置类型
Numbers: 编译期间的数字类型的常量
- int: 不大于64位,具体取决于平台
- double: 64位
int 类实现了位移运算符;
支持0x十六进制;
浮点型支持科学计数法Strings: UTF-16 unicode 编码
语法跟python类似
- &{express} 可以嵌入变量或者表达式
- ”’ ”’ 或者 “”” “””,可以多行显示
- r”, raw字符串
- In Dart, runes are the UTF-32 code points of a string.
Booleans: 同样是编译期间常量。
- bool 标识符,true & false
- if (nonbooleanValue) 这样比较是不行的,必须显示的比较或者调用类isEmpty方法。
Lists: 数组
- 如果想要声明一个编译期常量的数组:var constantList = const [1, 2, 3]; //必须指定为const
Maps: 字典 同js
Runes: UTF-32 字符串。比如一些符号,表情等。\uXXXX
Symbols: 不会用到。针对API推断标识符有用。
函数
Dart是一个真正的面向对象编程语言,一切都是对象,函数也是一个对象,它的类型是Function。
跟c语言函数语法一样,但是可以省略返回值类型和参数类型。
也有自己的速写语法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
等价于
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
=> expr 是 { return expr; } 的简写。expr只能是一个语句,否则必须用{}方式。
一、参数
1. 函数调用时,可以使用 name:value方式制定参数。顺序可以不是声明顺序。
2. @require 关键字,标示该参数必须传入。
3. 可选参数,使用[]扩起来。必须放到参数的最后位置,且不能存在多个[]的可选位置参数。
4. 参数可以设置默认值,如果没有设置默认值,默认为null。
二、.. 操作符,可以看作是链式编程的语法。object.func1()..func2()..func3();
三、函数可以作为参数传递给函数,作用同对象参数一样。
四、匿名函数、lambda表达式、闭包。是一个概念。
五、返回值:所有函数都有一个返回值,默认返回return null;
运算符
很多操作跟c运算符一致,这里不做过多介绍。下面只介绍特殊运算符:
~/: 除法,返回整数
as: 类型判断
is、is!: 类型检测
..: 严格来说,double dot不是操作符,而是Dart的语法。对同一个对象做一系列操作,类似链式编程。
??=: 赋值,只有当左值为null的时候,才赋值。
// 只有当b是null的时候,给b赋值value; 否则b保持原值不变
b ??=: value;
??: 条件运算符,简化if..else语句。expr1 ?? expr2,如果expr1不为null, 返回expr1; 否则返回expr2。
?.: 类似.操作符,获取成员。问号的作用是标示对象可以是null
控制流
- if..else: 条件必须是boolean类型
- for:
- 传统for语法
- for-in:可迭代的类或者类型才支持。例如:List, Set等
- While and do-while
- Break and continue
- Switch and case: int和string都可以作为case条件;每个case后必须有break语句;不支持空case;
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
- Assert
异常处理
- Throw: 可以抛出非null的任何对象,包括exception和error对象。
- Catch: 语法如下:
on
可以捕获具体类型的exception;catch 可以跟on一起,也可以单独使用。最多包含两个参数,e
是抛出的异常,s
是堆栈信息。
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
- rethrow: 再次抛出异常
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
- Finally: 捕获异常后后会继续执行finally中的内容。
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}
类
- 使用类成员: 使用.运算符引用对象成员和方法。
// If p is non-null, set its y value to 4.
p?.y = 4;
- 使用构造函数: Dart 2中new操作符可选。构造函数可以是类名,也可以是类名.标识符。
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
获取对象类型:使用runtimeType属性。(Object对象定义,获取运行时对象类型)
成员变量
没有public、private、protected关键字。
不需要设置成员变量默认值,不初始化的变量默认null。
默认会对成员变量生成隐式的get和set方法。构造函数
构造函数可以是跟类名一样的名字,也可以声明其他名字。
class Point {
num x, y;
Point(num x, num y) {
// Use this only when there is a name conflict
this.x = x;
this.y = y;
}
// Syntactic sugar for setting x and y
// before the constructor body runs.
// Point(this.x, this.y); 等同于上面的构造函数,写法更简单
// Named constructor:使用:Point p = Point.origin();
Point.origin() {
x = 0;
y = 0;
}
}
如果不写构造函数,会默认生成一个构造函数;默认生成的构造函数跟类同名,没有参数。
构造函数不能继承。默认子类会调用基类的默认构造函数或者无参数构造函数。
跟C++一样,Dart也有初始化列表(initializer list)。初始化列表要写在调用基类构造函数之前。
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
重定向构造函数:重定向构造函数的函数体必须为空,通过冒号在后面定向到其他构造函数.
class Point {
num x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
常量构造函数:可以创建一个编译时的常量对象,对象构造函数参数必须时常量。用于创建一个不变的对象(内部成员不会改变)
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
工厂构造函数:不能直接使用this。可以从cache获取实例,也可能创建子类型的对象。
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) {
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);
}
}
- 成员函数
getter和setter方法,是默认生成用于存取成员变量的成员函数。也可以显式声明(使用get和set关键字)
class Rectangle {
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}
抽象方法:类似C++中的虚基类中的虚函数,基类中没有实现,子类实现。
抽象类:
跟C++不同的是,可以通过工厂构造函数(factory constructor)创建实例。隐含接口(Implicit interfaces):使用implements关键字,可以实现类的方法,可以实现多重继承。
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _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.';
}
// An implementation of the Person interface.
class Impostor implements Person {
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()));
}
class Point implements Comparable, Location {...}
扩展一个类
关键字extends创建子类,使用super指向其基类。
@override 关键字用来覆盖基类的实现。
covariant 关键字:表示收紧子类型class Animal { void chase(Animal x) { ... } } class Mouse extends Animal { ... } class Cat extends Animal { //只能传Mouse和其子类 void chase(covariant Mouse x) { ... } }
不能访问一个不存在的成员函数,但是可以通过覆盖noSuchMethod()方法,使代码不抛出异常。
枚举类型:可以表示固定的常数的一种特殊的类。默认值index从0开始。
enum Color { red, green, blue } //使用enum关键字定义枚举 assert(Color.red.index == 0); assert(Color.green.index == 1); assert(Color.blue.index == 2);
枚举类型使用的限制:
- 不能继承,混合和实现一个枚举。
- 不能显式的实现一个枚举类。
向类中添加特性:使用mixins技术(类似多重继承)
关键字with
class T = A with S;
那我们得到的class T是怎么样的呢?假设MA表示A中的所有方法,MS表示S中的所有方法,那么T中的方法集合为:MS U (MA - MS)
。复杂一点的情况:
class T = B with A, S;
==class T = (B with A) with S;
类成员和方法:同样使用
static
关键字。
泛型
可以在运行时判断泛型类型内容的具体type。其他方面跟java或者c++差不多。
库和可见性
- 使用import导入要使用的库。
- 如果导入的多个库中,有同名类或者函数,可以通过别名区分。关键字as。类似c++中的namespace。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
- 也可以仅仅导入库中的部分内容
show
和hide
关键字
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
- 懒加载库
deferred as
关键字
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
- 如何实现库。单独章节进行讲解。
异步支持
关键字async
和await
支持异步编程。
生成器
参考python中的生成器。
需要后续加强了解
可调用的类
Dart 语言中为了能够让类像函数一样能够被调用,可以实现call()方法。
具体使用的场景,需要调研
隔离
沙盒?
Typedefs
Dart中,函数也是对象。Function关键字,typedefs 可以给函数设置别名。
元数据
A metadata annotation begins with the character @, followed by either a reference to a compile-time constant (such as deprecated) or a call to a constant constructor.
Two annotations are available to all Dart code: @deprecated and @override.
注释
- 单行
//
- 多行
/* */
- 文档注释
///
或者/**