/ 入门简单的Dart程序 /
// 定义一个函数
printNumber(int number){
print('The number is $number.'); // 打印到控制台。
}
// 入口函数
void main(){
var number = 42;// 声明并初始化一个变量。
printNumber(number);// 调用函数。
}
// 代码注释。
$variableName (或 ${expression}) 获取变量值
/ 重要概念 /
在学习 Dart 语言时, 应该基于以下事实和概念:
-
万物皆对象, 无论是数字,函数和null都是对象。所有对象继承自Object类。
-
尽管Dart语言是强类型的, 但是Dart可以推断类型, 上面的var number等价于int number。
-
针对于不确定的数据类型,请使用dynamic。
-
Dart支持泛型, 如List(整数列表)和List(任何类型的对象列表)。
-
与Java不同, Dart中没有权限关键字"public", “protected”, “private”。如果标识符以下划线(_number)开头, 则认为是私有属性。
-
Dart语言定义的变量,如果不赋值,默认为空null。
/ 变量 /
Dart内建数据类型如下:
- Number 通过num声明
- int 整数值
- double 双精度浮点值
void main() {
var number = 1; // Dart会自动推断为int类型
int value = 1; // 显示声明为int类型
print(number == value); // 该值应为true, 因为上述两个变量的值和类型相同
var pointNumber = 1.0; // Dart会自动推断为double类型
double pointValue = 1.0; // 显示声明为double类型
double pointValueCast = 1; // Dart2.1之后会自动转换为为double类型
print(pointNumber == pointValue); // 该值应为true, 因为上述两个变量的值和类型相同
print(pointNumber == pointValueCast); // 该值应为true, 因为上述两个变量的值和类型相同
}
- String
- 以单引号或者双引号包裹。
- 可以通过"+"连接。
- 可以通过 v a r i a b l e N a m e 或 者 variableName或者 variableName或者{expression}获取取值。
- 使用r前缀创建原始字符串。
- 对象的常用方法请查阅String常用方法
void main() {
var s1 = "我是字符串1";
String s2 = "我是字符串2";
// s3虽然手动换行,但是输出的时候还是在一行
var s3 = '我是'
'字符串'
'3';
// s4和s5为多行字符串
var s4 = """
我是
字符串
4
哈哈哈
""";
var s5 = '''
我是
字符串
4
哈哈哈
''';
// s6会换行
var s6 = "In a raw string, even \n isn't special.";
// s7保持原样输出
var s7 = r"In a raw string, even \n isn't special.";
print(s1);
print(s2);
print(s3);
print(s4);
print(s5);
print(s6);
print(s7);
}
/* console
我是字符串1
我是字符串2
我是字符串3
我是
字符串
4
哈哈哈
我是
字符串
4
哈哈哈
In a raw string, even
isn't special.
In a raw string, even \n isn't special.
*/
- Boolean
- Dart 使用 bool 类型表示布尔值。Dart 只有字面量 true and false 是布尔类型, 这两个对象都是编译时常量。
void main() {
var b = true;
var c = false;
bool d; // 声明变量不赋值的情况下,默认为null
bool e = true;
print(b);
print(c);
print(d);
print(e);
}
/* console
true
false
null
true
*/
- List
- 几乎每种编程语言中最常见的集合可能是array或有序的对象集合。在Dart中的Array就是List对象, 通常称之为List。
void main() {
void main() {
var list = [1, 2, 3];
List list1 = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
}
- Set
- 在Dart中Set是一个元素唯一且无序的集合。
void main() {
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
// Dart 推断 halogens 类型为 Set<String> 。如果尝试为它添加一个 错误类型的值,分析器或执行时会抛出错误。
halogens.add('haha'); // 添加成功
// halogens.add(1); // 类型错误,编译时提示
// 要创建一个空集,使用前面带有类型参数的 {} ,或者将 {} 赋值给 Set 类型的变量
var names = <String>{};
Set<String> names1 = {}; // 这样也是可以的。
// var names = {}; // 这样会创建一个 Map ,而不是 Set 。
var elements = <String>{};
// 使用 add() 或 addAll() 为已有的 Set 添加元素
elements.add('fluorine');
elements.addAll(halogens);
// 使用 .length 来获取 Set 中元素的个数
assert(elements.length == 5);
}
- Map
- Map是用来关联keys和values的对象。keys和values可以是任何类型的对象。
- 在一个Map对象中一个key只能出现一次。但是value可以出现多次。
void main() {
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
// 以上 Map 对象也可以使用 Map 构造函数创建
var gifts1 = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases2 = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
// 赋值
gifts['fourth'] = 'calling birds';
// 从一个 Map 中获取一个 value
var first = gifts['first'];
// 获取Map的长度
print(gifts.length);
}
- Rune和Symbol
- 不常用,有兴趣可以自行学习。
- 通过Symbol声明的变量, 通过#variableName调用
/ final和const /
-
使用过程中从来不会被修改的变量, 可以使用final或const, 而不是var或者其他类型。
-
final变量的值只能被设置一次; const变量在编译时就已经固定(const变量是隐式final类型)。
void main() {
final name = 'Bob';
final String nickname = 'Bobby';
// name = 'Jack'; // Error: 一个 final 变量只能被设置一次。
// const是编译时就固定值
const bar = 1000000; // 压力单位 (dynes/cm2)
const double atm = 1.01325 * bar; // 标准气压
// Const 关键字不仅可以用于声明常量变量。 还可以用来创建常量值。
var foo = const []; // 等价于 var foo = [];
final bar1 = const [];
const baz = []; // Equivalent to `const []`
// 非 Final , 非 const 的变量是可以被修改的,即使这些变量 曾经引用过 const 值。
foo = [1, 2, 3]; // 曾经引用过 const [] 常量值。
// final和const修饰的不能修改
// bar1 = [1]; // 编译时报错, final修饰的不可修改
// baz = [2]; // 编译时报错, const修饰的不可修改
}
/ 函数 /
- Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象, 并且有它的类型Function。
- 这也意味着函数可以被赋值给变量或者作为参数传递给其他函数。也可以把Dart类的实例当做方法来调用。
// 有返回值的函数
bool showPrice() {
return true;
}
// 返回值为void
void printVoidNumber() {
print('return void');
}
// 返回值为void, 此时void的可以省略
printVoidNumber1() {
print('return void');
}
// 如果一个函数函数体只有一行,可以用箭头代替大括号
// => expr 语法是 { return expr; } 的简写。 => 符号 有时也被称为 箭头 语法。
showBooleanValue() => true;
// 将函数赋值给一个变量
var a = showBooleanValue();
void main() {
print(a);
}
- 可选参数
- 命名可选参数, 放在大括号内{}
void enableFlags({bool bold, bool hidden}) {}
位置可选参数, 放在中括号内[]
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
// 方法调用
void main() {
say('Bob', 'Howdy'); //不使用可选参数
say('Bob', 'Howdy', 'smoke signal'); //使用可选参数
}
- 默认参数值
/// 设置 [bold] 和 [hidden] 标志 ...
void enableFlags({bool bold = false, bool hidden = false}) {}
void main(){
// bold 值为 true; hidden 值为 false.
enableFlags(bold: true);
}
- 函数是一等公民
- 一个函数可以作为另一个函数的参数。
- 同样可以将一个函数赋值给一个变量。
printElement(int element) => print(element);
void mian(){
var list = [1, 2, 3];
// 将 printElement 函数作为参数传递。
list.forEach(printElement);
}
- 匿名函数
void main() {
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
}
- 闭包:其实闭包就是在一个函数中可以调用其他的函数,这样其他的函数可以使用本函数的参数及其他内容。
/ 运算符 /
- 类型判断运算符
- as 类型转换
- is 判断是否为某类型
- is! 判断不是某类型
- 赋值运算符
- a = value; 将value赋值给便里昂a
- b ??= value; 如果b为空时, 将value赋值给b, 否则b的值保持不变。
- 条件表达式
- condition ? expr1 : expr2 如果条件为 true, 执行 expr1 (并返回它的值):否则, 执行并返回 expr2 的值。
- expr1 ?? expr2 如果 expr1 是 non-null, 返回 expr1 的值; 否则, 执行并返回 expr2 的值。
- 级联运算符
- 可以实现对同一个对象进行一系列的操作。
- 除了调用函数, 还可以访问同一对象上的字段属性。这通常可以节省创建临时变量的步骤, 同时编写出更流畅的代码。
- 类似与build模式。
class Person{
int age;
String name;
Person({this.name, this.age});
void say(String words) {
print(name + words);
}
}
void main(){
Person() // 获取对象。
..name = 'Bob' // 调用成员变量。
..say('important');
// 等价于下面的代码
var person = Person(name: "Bob");
person.say('important');
// 级联运算符可以嵌套
/*final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();*/
// 在返回值为void的函数之后不能继续调用级联操作符
var sb = StringBuffer();
sb.write('foo') // write函数返回值是void, 不能再继续调用
..write('bar'); // 运行会报错
}
/ 控制流程语句 /
// if elseif else
weatherStatus(){
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
}
// for 循环
text(){
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('---$i!');
}
// for ... in ...
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}
// forEach
collection.forEach((item) => print(item));
}
// while 和 do-while
printSomethings() {
while (!isDone()) {
doSomething();
}
do {
printLine();
} while (!atEndOfPage());
}
// break 和 continue
pauseSomethings(){
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
// 执行yearsExperience大于等于5的元素
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
// 如果candidate对象实现了Iterable接口, 可以调用如下方式
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
}
// switch 和 case
judgeType() {
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED': // 当command为该种情况时,由于该分支没有break语句会继续执行下一个分支,直到遇到break停止执行。
executeDenied();
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
}
// assert 判断是否成立
judgeEquals() {
// 确认变量值不为空。
assert(text != null);
// 确认变量值小于100。
assert(number < 100);
// 确认 URL 是否是 https 类型。
assert(urlString.startsWith('https'));
// assert 的第二个参数可以为其添加一个字符串消息。
assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
}
/ 异常处理 /
- Dart 代码可以抛出和捕获异常。
- 异常表示一些未知的错误情况。如果异常没有被捕获, 则异常会抛出, 导致抛出异常的代码终止执行。
- throw 可以抛出Dart定义的异常, 也可以抛出任意对象
// 高质量的生产环境代码通常会实现 Error 或 Exception 类型的异常抛出。
throw FormatException('Expected at least 1 section');
throw 'Out of llamas!';
// 完整的try catch finally代码
try {
// 代码块
} on Exception catch (e) {
// 捕获到异常走这里
} finally {
// 无论是否捕获异常, 最终都会走这里
}
/ 类和构造函数 /
- 通过class关键字声明。
- 在没有声明构造函数的情况下, Dart会提供一个默认的构造函数。默认构造函数没有参数并会调用父类的无参构造函数。
class Point {
num x, y;
// 构造函数的第一种方法
Point(num x, num y) {
// 还有更好的方式来实现下面代码,敬请关注。
this.x = x;
this.y = y;
}
// 构造函数的第二种方法
Point(this.x, this.y)
// 构造函数的第三种方法--命名构造函数
Point.origin(){
x = 0;
y = 0;
}
}
- 类的继承
- 子类通过关键字extends继承父类。
- 默认情况下, 子类的构造函数会自动调用父类的默认构造函数(匿名, 无参数)。
- 如果父类没有匿名无参的构造函数, 则在子类中需要手动调用父类的构造函数。
class Person {
String firstName;
Person.fromJson(Map data){
print("I'm $firstName");
}
}
class Employee extends Person {
Employee.fromJson(Map data) : super.fromJson(data){
print("I'm Employee");
}
}
main() {
var emp = new Employee.fromJson({});
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
- 构造函数不仅可以调用父类构造函数, 还可以在构造函数体执行之前初始化成员变量。
import 'dart:math';
class Point {
final num x;
final num y;
final num distance;
Point(x, y)
: x = x,
y = y,
distance = sqrt(x * x + y * y);
}
- 重定向构造函数
class Point {
num x, y;
// 类的主构造函数。
Point(this.x, this.y);
// 指向主构造函数
Point.alongXAxis(num x) : this(x, 0);
}
- 常量构造函数
- 如果该类生成的对象是固定不变的, 那么就可以把这些对象定义为编译时常量。
- 为此需要定义一个const构造函数, 并且声明所有实例变量为final。
class ImmutablePoint {
static final ImmutablePoint instance =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
- 工厂构造函数
- 当执行构造函数并不总是创建这个类的一个新实例时, 则使用 factory 关键字。
- 一个工厂构造函数可能返回一个cache中的实例。
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);
}
}
- Getter 和 Setter方法
class Person {
num age;
final String name;
final String hobby;
// Getter
String get hobby => "basketball";
// Setter
set hobby(String hobbyName) => hobby = hobbyName;
Person(this.name, this.age)
}
- abstract 和 implements
- abstract抽象类, 类中的抽象方法通过分号结束, 不用实现函数体, 故可以省略大括号。
- implements实现接口。每个类都隐式的定义了一个接口, 接口包含该类所有的成员及其实现的接口。
// 抽象类
abstract class Person {
void walk(); // 抽象方法
}
class Animal {
void fly() => print("I can fly");
}
class Bird implements Animal {
void fly() {
// 具体实现
}
}
- 重写运算符 通过operator重写
class Vector {
final int x, y;
Vector(this.x, this.y);
// 返回值 operator 运算符(参数) {具体实现}
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}
- noSuchMethod()
- 当代码尝试调用类中不存在的方法时, 会抛出NoSuchMethodError异常, 可以通过重写该方法实现自己想要的结果。
class Animal {
@override
void noSuchMethod(Invocation invocation){
// 具体实现
}
}
- 枚举类型
enum Color {
RED, GREEN, BLUE
}
- Mixin为类添加新功能
- Mixin是复用类代码的一种途径, 复用的类可以不存在继承关系。
- 通过with后面跟一个或者多个类进行复用。
- 通过mixin定义一个Mixin类, Mixin类通过on复用其他类
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
mixin MusicalPerformer on Musician {}
- 静态变量和静态类型
class Musician extends Performer with Musical {
class Animal {
static const height = 180;
static num distance(){
return 100;
}
}
/ 库 /
// 通过import导入
import 'dart:html';
// 通过as指定别名, 调用时通过lib2调用
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;
// 延迟加载库, 当使用时进行加载
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
// 使用时使用loadLibrary()加载
await hello.loadLibrary();
hello.printGreeting();
}
/ 异步(Future和Stream) /
- Future 使用async 和 await 构造。
Future<bool> downLoad(String url) async {
val result = await down();
return result;
}
- Stream能够多次响应事件, 比如下载进度回调常用。
- 有个博客介绍的比较详细, 请查看Future使用和Stream介绍
/ typedefs /
为函数定义别名
typedefs Compare = int Function(T a, T b);
/ 注释 /
// 单行注释
/*
多行注释
多行注释
多行注释
*/
/// 文档注释
/// 文档注释
/**
* 文档注释
*/