hello world
重要的概念
- 能赋值给变量的所以东西都是对象,包括 numbers, null, function, 都是继承自 Object 内置类
- 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)
- dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度
- dart 提供了顶级函数(如:main())
- dart 没有 public、private、protected 这些关键字,变量名以"_"开头意味着对它的 lib 是私有的
变量
没有初始化的变量都会被赋予默认值 null
var name = 'Bob';
var unInitializeValue1;
程序中只当数据类型是为了指出自己的使用意图,并帮助语言进行语法检查。但是,指定类型不是必须的
num
string
- '''...''',"""..."""表示多行字符串
- r'...',r"..."表示“raw”字符串
- 用 $ 或 ${} 来计算字符串中变量的值
bool
- Dart 是强 bool 类型检查,只有bool 类型的值是true 才被认为是true
list
list 基本和 JavaScript 数组一样,它的方法如下:
map
类似 JavaScript map
注:如果定义了一个 map 常量,那么value 也必须是常量
symbol
symbol字面量是编译时常量,在标识符前面加#。如果是动态确定,则使用Symbol构造函数,通过new来实例化
函数
所有的函数都会有返回值。如果没有指定函数返回值,则默认的返回值是null。没有返回值的函数,系统会在最后添加隐式的return 语句。
函数参数
函数可以有两种类型的参数:
- 必须的——必须的参数放在参数列表的前面。
- 可选的——可选的参数跟在必须的参数后面。
注:可选参数必须放在最后
通过【】来表示可选参数
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
还可以设置默认参数值
String say(String from, String msg,
[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
函数还可以作为另一个函数的参数
printElement(element) {
print(element);
}
var list = [1, 2, 3];
函数可以匿名,但是不像 JavaScript, 匿名函数不用加上 function 关键字
var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
list.forEach((i) {
print(list.indexOf(i).toString() + ': ' + i);
});
闭包
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
运算符
除了常见的,还有如下运算符:
如果 emp 为空或者不是 Person 的实例,会抛出异常
-
??= 运算符
b ??= value;
-
?? 运算符
String toString() => msg ?? super.toString();
-
.. 运算符,把对同一对象的不同操作串联起来
final addressBook = (new AddressBookBuilder()
..name = 'jenny'
..email = '[email protected]'
..phone = (new PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
流程控制语句
- if...else
- for
- while do-while
- break continue
- switch...case 如果 case 后面有表达式但是没有 break,会抛出异常
- assert(仅在checked模式有效),如果条件为假,抛出异常
异常
throw
-
抛出固定类型的异常:
throw new FormatException('Expected at least 1 section');
-
抛出任意类型的异常:
throw 'out of llamas!'
-
因为抛出异常属于表达式,可以将throw语句放在=>语句中,或者其它可以出现表达式的地方:
distanceTo(Point other) =>
throw new UnimplementedError();
catch
可以向catch()传递1个或2个参数。第一个参数表示:捕获的异常的具体信息,第二个参数表示:异常的堆栈跟踪(stack trace)
rethrow
rethrow语句用来处理一个异常,同时希望这个异常能够被其它调用的部分使用
finally
Dart 的finally用来执行那些无论异常是否发生都执行的操作。
类
使用new语句来构造一个类。构造函数的名字可能是ClassName,也可以是ClassName.identifier
var jsonData = JSON.decode('{"x":1, "y":2}');
- 使用.来调用实例的变量或者方法。
- 使用 ?. 来避免左边操作数为null引发异常。
- 使用const替代new来创建编译时的常量构造函数。
- 两个使用const构建的同一个构造函数,实例相等。
- 获取对象的运行时类型使用:o.runtimeType
所有实例变量会生成一个隐式的getter方法,不是final或const的实例变量也会生成一个隐式的setter方法
构造函数
class Point {
num x;
num y;
构造函数不能被继承
子类不会继承父类的构造函数。如果不显式提供子类的构造函数,系统就提供默认的构造函数。
命名构造函数
class Point {
num x;
num y;
Point(this.x, this.y);
使用命名构造函数可以实现一个类多个构造函数。构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类实现这个构造函数
如果父类不显式提供无参的非命名构造函数,在子类中必须手动调用父类的一个构造函数。在子类构造函数名后,大括号{前,使用super.调用父类的构造函数,中间使用:分割
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
当在构造函数初始化列表中使用super()时,要把它放在最后。
View(Style style, List children)
: _children = children,
super(style) {}
除了调用父类的构造函数,也可以通过初始化列表 在子类的构造函数体前(大括号前)来初始化实例的变量值,使用逗号,分隔
class Point {
num x;
num y;
Point(this.x, this.y);
工厂构造函数
当实例化了一个构造函数后,不想每次都创建该类的一个新的实例的时候使用factory关键字,定义工厂构造函数,从缓存中返回一个实例,或返回一个子类型的实例
class Logger {
final String name;
bool mute = false;
static final Map<String, Logger> _cache = <String, Logger>{};
方法
Getters and setters
get()和set()方法是Dart 语言提供的专门用来读取和写入对象的属性的方法。每一个类的实例变量都有一个隐式的getter和可能的setter(如果字段为final或const,只有getter)
抽象类
使用abstract关键字定义一个抽象类,抽象类不能实例化。抽象类通常用来定义接口。
隐式接口
每一个类都隐式的定义一个接口,这个接口包含了这个类的所有实例成员和它实现的所有接口
一个类可以实现一个或多个(用,隔开)接口,通过implements关键字。
class Person {
final _name;
Person(this._name);
String greet(who) => 'hello,$who,i am $_name';
}
class Imposter implements Person {
final _name = '';
String greet(who) => 'hi $who.do you know who i am.';
}
greetBob(Person p) => p.greet('bob');
main(List<String> args) {
print(greetBob(new Person('lili')));
print(greetBob(new Imposter()));
}
继承
使用extends来创造子类,使用super来指向父类
枚举类型
枚举类型是一种特殊的类,通常用来表示一组固定数字的常量值。
每个枚举类型都有一个index的getter,返回以0开始的位置索引,每次加1。
在switch语句中使用枚举,必须在case语句中判断所有的枚举,否则会获得警告。
枚举类型有以下限制:
- 不能继承,mixin,或实现一个枚举。
- 不能显式的实例化一个枚举。
泛型
使用<...> 的方式来定义泛型
虽然Dart 语言中类型是可选的,但是明确的指明使用的是泛型,会让代码更好理解
abstract class Cache<T> {
T getByKey(String key);
setByKey(String key, T value);
}
用于集合类型
泛型用于List 和 Map 类型参数化
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
泛型集合及它们所包含的类型
dart的泛型类型是具体的,在运行时包含它们的类型信息。
库和可见性
使用import 和 library 指令可以方便的创建一个模块或分享代码。一个Dart 库不仅能够提供相应的API,还可以包含一些以_开头的私有变量仅在库内部可见
如果导入的库拥有相互冲突的名字,使用as为其中一个或几个指定不一样的前缀。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
如果只需要使用库的一部分内容,使用show或hide有选择的导入。
要延迟加载一个库,首先必须使用deferred as导入它。
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
可以在代码中多次调用loadLibrary()方法。但是实际上它只会被执行一次。
使用延迟加载的注意事项:
- 延迟加载的内容只有在加载后才存在。
- Dart 隐式的将deferred as改为了deferred as namespace。loadLibrary()返回值是Future
异步支持
使用async函数和await表达式实现异步操作。
当需要使用一个从Future返回的值时,有两个选择:
- 使用async和await。
- 使用Future API。
当需要从一个Stream获取值时,有两个选择:
给函数添加async关键字将使函数返回一个Future类型。
在Stream中使用异步循环
异步循环的执行流程如下:
- 等待 stream 发出数据。
- 执行循环体,并将变量的值设置为发出的数据。
- 重复1.,2.直到stream 对象被关闭
注:这个过程类似于 JavaScript 的 Rxjs
可调用类
Dart 语言中为了能够让类像函数一样能够被调用,可以实现call()方法。
class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
请发表评论