Flutter 基础—— Dart 入门
Flutter简介
Flutter是Google公司2018年2月27日发布的第一个开源跨平台软件开发工具包 (SDK),支持Android、iOS两个平台,可实现高性能、高保真的应用程序开发。开发者借助Flutter开发平台可轻松实现自己的应用,其开发框架默认支持了Material(类似Google设计风格)和Cupertion(类似iOS设计风格)两种风格,且无论从UI样式、用户体验上都非常接近原生应用。
经过近7个月的优化改进2018年9月19日Google公司在上海正式发布非常接近1.0正式版本的Flutter Release Preview 2。基于其优越性能Flutter有望成为未来应用开发的主流工具。
Flutter类似且优于Html、React Native、Weex等跨平台解决方案。ReactNative将JSX生成的代码最终都渲染成原生组件,JS与原生通过JSBridge传递数据。而Flutter则采用完全不同的设计,底层是一套独立的渲染引擎–Skia,所有组件也都是独立于平台的Widget组件,可以在最大程度上保证了跨平台体验的一致性。

Dart
Flutter 使用 Dart 作为开发语言,在深入flutter框架前应该先对dart语言有所了解。据说,dart语言里的API 90%以上与 Java 相同,如果你有 Java 基础,几乎可以很快上手,没有 Java 基础也不用担心,它的 API 很简单,学过 JavaScript 也可以轻松get✅;
几个重要的点:
- 能赋值给变量的所以东西都是对象,包括 numbers, null, function, 都是继承自 Object 内置类
- 尽管 dart 是强类型的,但类型注释是可选的,因为 dart 可以类型推断,如果要明确说明不需要任何类型,请使用特殊类型dynamic。
- 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)
- dart支持泛型类型,如
List <int>(整数列表)或List <dynamic>(任何类型的对象列表)。
- 支持最外层函数定义,也支持类的静态方法与对象的实例方法,函数中可定义内部函数
(Dart支持顶级函数(例如main()),以及绑定到类或对象的函数(分别是静态和实例方法)。您还可以在函数内创建函数(嵌套函数或本地函数))。
- dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度
- dart 没有 public、private、protected 这些关键字,变量名以"_"开头意味着对它的 lib 是私有的
- 标识符以字母或“_”开头,后面可随意组合
这里简单介绍下:
-
Hello World
-
变量声明
-
数据类型
-
函数
-
流程控制
-
异常处理
-
类
-
泛型
-
异步操作
1. Hello World
main(List<String> args){
print("Hello World");
}
和 Java 程序一样,dart程序也有一个入口函数 main ,把上面的程序保存为hello_world.dart, 在命令行运行:
安装之后需要配置环境变量
启动 dart 程序
// 定义一个函数
printNumber(num aNumber) {
print("The number is `${aNumber}`."); //控制台打印
}
// 启动
main() {
var number = 42;
printNumber(number);
}
2. 变量声明
变量声明关键字: var 、const、 final 、int 、String、 double(浮点型)、 bool
2.1 var 声明变量 —— 不指定类型
和 JavaScript 一样, 可以用 var 声明变量
main(List<String> args) {
var number = 18;
var name ="xiao ming";
var salary = 150300.56;
var isDoorOpen = true;
}
不一样的是,dart自带类型推断,一旦给变量赋值,它的类型就不可变了。
尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)
dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度。
//类似于 typescript, 可以推导出 name 为字符串类型
var name = "Bob";
// 如果不想 推导出类型,下边两种写法:
dynamic name = "Bob";
Object name= "Bob";
2.2 int 、String、 double(浮点型)、 bool声明变量——指定变量类型
数值类型num,有两个子类int,double,int可进行按位运算,没有基本类型的概念,由于int,double都是num的子类,定义为num的变量可以在int、double间多态
main(List<String> args) {
int number = 18;
String name = "xiaoming";
double salary = 150300.56;
bool isDoorOpen = true;
}
2.3 const和final声明常量
main(List<String> args) {
final int number = 42;
const String name = "xiao ming";
//Omit explicitly defining data types
final salary = 150300.56;
const isDoorOpen = true;
}
const是编译时常量,在编译时确定,不可定义为实例变量;final是运行时常量,在第一次使用时确定;一个常量是const类型也暗示必然是final类型
const也可定义为其它const的算式结果,在类中定义需与static一起
const可写在变量或构造函数前用来定义常值,常量表示引用关系不可变,常值表示值本身不可变
3. 数据类型
3.1 dart提供基本的数据类型:
- Numbers
- Strings
- Booleans
- Lists
- Maps
- Runes(字符)
- Symbol(符号)
main(List<String> args) {
//Numbers
int x = 100;
double y = 1.1;
int z = int.parse('10');
double d = double.parse('44.4');
//Strings
String s = "This is a string";
String backslash = "I can't speak";
//String interpolation
String interpolated = "Value of x is $x"; //Prints: Value of x is 100
String interpolated2 = "Value of s is ${s.toLowerCase()}";
//Prints: Value of s is this is a string
//Booleans
bool isDoorOpen = false;
}
3.2 常用方法
3.2.1 number 取值范围:-2^53 to 2^53
// String -> int
var one = int.parse('1');
// String -> double
var onePointOne = double.parse('1.1');
// int -> String
String oneAsString = 1.toString();
// double -> String 注意括号中要有小数点位数,否则报错
String piAsString = 3.14159.toStringAsFixed(2);
3.2.2 string
- '''...''',"""..."""表示多行字符串(连续三个单引号或双引号)
- r'...',r"..."表示“raw”字符串(字符串前加字母 r 则不处理转义)
- 可用
${}引用表达式,或直接$引用标识符
示例代码:
String s = "FRONT END DEVELOPER";
print ("A Commpany has a $s, which is good idea." ==
"A Commpany has a Front End Developer," +
" which is good idea.");
print("I am a " +
"${s.toUpperCase()} is very hornor!" ==
"I am a " +
"FRONT END DEVELOPER is very hornor!");
3.2.3 bool
Dart 是强 bool 类型检查,只有bool 类型的值是true 才被认为是true
3.2.4 List
声明 List 用 new List() 或者简单的赋值
下面是一些基本操作
main(List<String> args) {
// 声明
var vegetables = new List();
//或者简单赋值声明
var fruits = ["apples", "peaches"];
// 添加元素
fruits.add("bananas");
// 添加多个元素
fruits.addAll(["grapes","oranges"]);
// 获取第一元素
fruits.first
// 获取最后一个元素
fruits.last
// 查找某个元素的索引号
assert(fruits.indexOf("apples") === 0);
// 删除指定位置的元素,返回删除的元素
fruits.removeAt(index);
// 删除指定元素,成功返回 true ,失败返回 false
fruits.remove("oranges");
// 删除最后一个元素,返回删除的元素
fruits.removeLast
// 删除指定范围的元素,含头不含尾。成功返回 null
fruits.removeRange(start, end);
// 删除指定条件的元素,成功返回null
fruits.removeWhere((item) => item.length > 6);
//删除所有元素
fruits.clear();
// sort()排序 传入一个函数作为参数,return <0 表示有小到大,>0 表示由大到小;
fruits.sort((a, b) => a.compareTo(b));
//常量 List
var list = const [1,2,3,4]; //Cannot alter elements of this list
}
3.2.5 map 散列表
基本操作
// 声明
// 简单赋值
var smartHomeProducts = {
"largeAppliances": ["air conditioning", "television", "fridge"],
"homeDevices": ["air purifier","Sweeping robot", "humidifier"]
}
var searchTerms = new Map();
// 指定键值对的参数类型
var smartHomeSkills = new Map<int, String>();
// 取值
print(smartHomeProducts["largeAppliances"]); // Output: ["air conditioning", "television", "fridge"];
// 不存在的 key 返回 null
print(smartHomeProducts["kitchenAppliances"]); // Output: null;
// Map的赋值,中括号中是Key,这里可不是数组
smartHomeSkills[1] = "chart";
//Map中的键值对是唯一的
//同Set不同,第二次输入的Key如果存在,Value会覆盖之前的数据
smartHomeSkills[1] = "sing";
assert(smartHomeSkills[1] == "sing");
// 检索Map是否含有某Key
assert(smartHomeSkills.containsKey(1));
//删除某个键值对
smartHomeSkills.remove(1);
assert(!smartHomeSkills.containsKey(1));
// 获取所有值
var entries = smartHomeProducts.entries;
var values = smartHomeProducts.values;
print(entries); // Output: (MapEntry(largeAppliances: [air conditioning, television, fridge]), MapEntry(homeDevices: [air purifier, Sweeping robot, humidifier]))
print(values); // Output: ([air conditioning, television, fridge], [air purifier, Sweeping robot, humidifier])
// 常量map
var squares = const { //Cannot change the content of this map
2: 4,
3: 9,
4: 16,
5: 25
};
4. 函数
Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function。这意味着函数可以分配给变量或作为参数传递给其他函数。您也可以像调用函数一样调用Dart类的实例。
函数声明无需 function 关键字;
函数名前可标注函数返回类型,没有返回值的函数返回类型可设为void;
函数的参数可设定类型也可以不设
main(List<String> args) {
var name = fullName("John", "Doe");
print(name);
}
String fullName(String firstName, String lastName) {
return "$firstName $lastName";
}
//或忽略返回类型
fullName(String firstName, String lastName) {
return "$firstName $lastName";
}
支持箭头函数
fullName(String firstName, String lastName) => "$firstName $lastName";
命名参数
顾名思义:调用命名参数的函数时,必须指定参数的名字;
- 命名参数的启用,只需把所有参数用大括号包裹起来即可;
fullName({String firstName, String lastName}) {
return "$firstName $lastName";
}
main(List<String> args) {
var name = fullName(firstName: "John", lastName: "Doe");
print(name);
}
调用命名参数的函数时,如果没有指定参数的名字,程序会崩溃报错。
参数默认值
为命名参数的某个参数指定默认值,这个参数就会变成可选参数。如上面的函数指定默认参数后可以这样调用:
main(List<String> args) {
var name = fullName(firstName: "John");
print(name);
}
fullName({String firstName, String lastName = "Doe"}) {
return "$firstName $lastName";
}
5. 流程控制
- if...else if... else...
- 三元表达式
- for
- while/do...while
- switch...case..
...
这个流程控制语句使用和 JavaScript 没什么差异
6. 异常处理
try...catch...finaly
也跟 JavaScript 差不多。。。
7. 类 Class
7.1 类的定义
7.1.1 一个简单的类
//一个简单的类
class Point {
num x;
num y;
}
void main() {
var point = Point();
point.x = 4; // Use the setter method for x.
assert(point.x == 4); // Use the getter method for x.
assert(point.y == null); // Values default to null.
}
还记得吗: dart中一切未赋值的变量值都是 null;
7.1.2 构造函数
通过创建一个与类同名的函数来声明构造函数;
class Cat {
String name;
int age;
Cat(String name, int age) {
this.name = name;
this.age = age;
}
}
void main() {
Cat Tom = new Cat("Tom", 2);
print(Tom.name);
}
dart 提供了语法糖,以更简单的方式来生成构造函数;
class Cat {
String name;
int age;
Cat(this.name ,this.age)
}
void main() {
Cat Tom = new Cat("Tom", 2);
print(Tom.name);
}
上面的代码只用一行代码就完成了构造函数,第一个参数,对应到name,第二个参数对应age;
实际上,dart 会为没有声明构造函数的类创建默认的构造函数,默认构造函数没有参数,并在超类中调用无参数构造函数。
命名构造函数(构造函数标识符)
class Cat {
String name;
int age;
Cat(this.name ,this.age)
Cat.newBorn(){
name = "Cherry";
age = 0;
}
}
void main() {
Cat Cherry = new Cat.newBorn();
print(Cherry.name);
}
上面的代码,构造函数有了一个名字(newBorn), 这样在初始化时更清楚使用了哪个类
7.2 继承
dart 的类通过 extends 关键字实现继承
如果没有特别指明,子类的构造函数中第一步会调用父类的默认构造函数
子类构造函数的执行顺序是:初始化字段表->父类构造函数->子类构造函数
调用父类构造函数
// 调用父类构造函数
class Cat {
String name;
int age;
Cat(this.name ,this.age)
Cat.newBorn(){
name = "Cherry";
age = 0;
}
}
class Garfield extends Cat{
Garfield(String name, int age): super(name,age)
}
void main() {
Cat Garfield = new Garfield("jiafei", 1);
print(Garfield.name);
}
Garfield类继承了Cat类,并且在Garfield的构造函数里用SUPER关键字调用了Cat类的构造函数,
重定向构造函数:有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。重定向构造函数的主体是空的,构造函数调用出现在冒号(:)之后。
main(List<String> args) {
Pug p = new Pug.small('Duffy');
print(p.name);
}
class Dog {
String name;
int age;
Dog(this.name, this.age);
Dog.newBorn() {
name = 'Doggy';
age = 0;
}
}
class Pug extends Dog {
Pug(String name, int age): super(name, age);
Pug.small(Stirng name): this(name, 1);
Pug.large(Stirng name): this(name, 3);
}
上面定义了两个命名构造函数, small 调用了自身的构造函数,而自身又调用了dog的构造函数。
任何构造函数都不会被继承,这意味着父类的命名构造函数不会被子类继承。如果希望使用父类中定义的命名构造函数创建子类,则必须在子类中用冒号手动指明调用父类构造函数。
class Employee extends Person {
// Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
7.3 类中的函数
main(List<String> args) {
Cat Tom = new Cat("Tom", 1);
Tom.eat();
}
class Cat {
String name;
int age;
Cat(this.name ,this.age)
Cat.newBorn(){
name = "Cherry";
age = 0;
}
eat(){
print("I like eating fish!");
}
}
main(List<String> args){
Cat Cherry = new Garfield.small("jiafei");
Cherry.eat();
}
// 父类 -- 猫
class Cat{
String name;
int age;
Cat(this.name, this.age);
Cat.newBorn(){
name="dahua";
age=0;
}
eat(){
print("I like eating fish!");
}
}
// 子类 -- 加菲猫
class Garfield extends Cat{
Garfield(String name, int age): super(name,age);
Garfield.small(String name, int age): this(name, 1);
Garfield.large(String name, int age): this(name, 3);
@override
eat(){
print("I like eating small can!");
}
}
7.4 getter setter
默认的情况下类里定义的任何变量都是可以访问的,如 dog.name,变量的值也可以直接读写。但是有时候不希望直接读写而是通过getter setter。dart里 是通过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;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
7.5 抽象方法和抽象类
抽象类使用 abstract 关键字定义,抽象方法只能存在于抽象类中;
除非定义了工厂构造函数,抽象类不能被实例化
抽象方法以(;)结尾,不写函数体,即不用实现它
abstract class Doer {
// 实例的变量和方法...
// 定义一个抽象方法,以(;)结尾,没有函数体.
void doSomething();
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供了函数体,所以这不是一个抽象方法
}
}
7.6 隐式接口
每个类都隐式定义一个接口,这个接口包含该类的所有实例成员及其实现的任何接口。
如果要在不继承B实现的情况下,创建支持B类API的A类,则A类应该实现B类的接口。
一个类通过implements语句实现接口
class Person{
final _name; // 这是一个接口,但只能在本类中访问
Person(this.name); // 这不是接口,因为它是构造函数
String greet(String who) => "Hello $who, I am $name"; // 这是接口
}
Class Imposter 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")));// Output: Hello, Bob. I am Kathy.
print(greetBob(Imposter())); // Output: Hi Bob. Do you know who I am?
}
7.7 noSuchMethod
检测是否使用了不存在的变量或方法,可以重写noSuchMethod方法,否则会抛出NoSuchMethodError这个异常;
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
@override
void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}
7.8 静态方法
在字段或方法前增加static关键字就变成了静态,如:
class Dog {
String name;
int age;
Dog(this.name, this.age);
static bark() {
print('Bow Wow');
}
}
main() {
Dog.bark();
}
静态变量在使用之前不会初始化。
静态方法(类方法)不对实例进行操作,因此无法访问它.
例如:
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
static num 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);//2.8284271247461903
}
7.9 枚举类型Enum
枚举类型(通常称为枚举或枚举)是一种特殊类,用于表示固定数量的常量值。
使用enum关键字声明枚举类型:
enum Color { red, green, blue }
枚举中的每个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。例如,第一个值具有索引0,第二个值具有索引1。
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
可以通过.values获取枚举类中所有值的列表
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
7.10 mixins 为类添加功能
mixins是一种在多层级结构类中重用代码的方法。
定义mixin:使用 mixin 关键字创建一个没有构造函数的扩展类来实现一个mixin。
使用mixin:通过with关键字后跟多个类名来使用mixin;
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
8. 泛型
Dart 支持泛型,在定义 List 和Map 类型时,可以手动指定其元素类型,类型一旦确定便不可更改,也不可向其中添加其他类型的变量。
如:
// 构造函数的参数化类型
var names = List<String>();// 代表字符串列表
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error
var gifts = Map<String, String>();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
gifts[17] = 'argon'; //Error
// 使用字面量集合
var name = <String>['Seth', 'Kathy', 'Lars'];
var gifts = <String>,<String>{
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
}
同时,使用字面量定义变量时,Dart 也可以进行类型推断,如var name = ['Seth', 'Kathy', 'Lars'],可以推断该 List 为 List<String>()类型;
不限定参数类型
如有一个类,管理一个数据,希望这个数据是任何类型。
main(List<String> args) {
DataHolder<String> dataHolder = new DataHolder('Some data');
print(dataHolder.getData());
dataHolder.setData('New Data');
print(dataHolder.getData());
}
class DataHolder<T> {
T data;
DataHolder(this.data);
getData() {
return data;
}
setData(data) {
this.data = data;
}
}
9. 异步支持
Dart 支持异步操作。
使用异步首先要导入异步库import: "dart/sync";
Dart 有丰富的库支持,这里先不讲了,开发 Flutter 时,用到再去查就行。
异步操作(函数)有两种返回类型: Future和Streams;
Future基于观察者模式。类似于JavaScript里的Rx和Promise,如果熟悉这两个,就很容易理解Future。
简单来说,Future定义了未来将要发生的事,例如:未来我们会得到一个值。
Future 是泛型,Future,需要指定未来返回值的类型。如:
import 'dart/async';
Future<String> getStory(){
return new Future<String>.delay(new Duration(milliseconds:2000), (){
return 'Here is the story';
})
};
main(){
getStory().then((value) => {
print(value);
}).catchError((error)=> {
print(error);
})
print('Another print statement.');
}
使用async/await 关键字执行异步操作,使用try,catch和finally来处理使用await的代码中的错误;
用async 关键字修饰函数体就声明了该函数是异步函数;
import 'dart/async';
Future<String> getStory(){
return new Future<String>.delay(new Duration(milliseconds:2000), (){
return 'Here is the story';
})
};
main() async{
try{
String result = await getStory();
print(result);
}catch(e){
print(e);
}
print('Another print statement.');
}
处理流 Stream
可用await for等待遍历stream的所有值,但要小心使用:
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
表达式的值必须具有Stream类型。执行过程如下:
- 等待流发出值。
- 执行for循环的主体,并将变量设置为发出的值。
- 重复1和2,直到流关闭。
要停止侦听流,您可以使用break或return语句,该语句将跳出for循环,并从流中取消订阅。
保证await、await for要处在异步操作中
参考文档:
- dart 官方文档:https://www.dartlang.org/guides/language/language-tour
- dart 中文文档:https://www.kancloud.cn/marswill/dark2_document
- 学习flutter必会的dart知识系列:https://zhuanlan.zhihu.com/p/38847885
- Dart 学习备忘录: https://zhuanlan.zhihu.com/p/39961580
Flutter 基础—— Dart 入门
Flutter简介
Flutter类似且优于Html、React Native、Weex等跨平台解决方案。ReactNative将JSX生成的代码最终都渲染成原生组件,JS与原生通过JSBridge传递数据。而Flutter则采用完全不同的设计,底层是一套独立的渲染引擎–Skia,所有组件也都是独立于平台的Widget组件,可以在最大程度上保证了跨平台体验的一致性。
Dart
Flutter 使用 Dart 作为开发语言,在深入flutter框架前应该先对dart语言有所了解。据说,dart语言里的API 90%以上与 Java 相同,如果你有 Java 基础,几乎可以很快上手,没有 Java 基础也不用担心,它的 API 很简单,学过 JavaScript 也可以轻松get✅;
几个重要的点:
List <int>(整数列表)或List <dynamic>(任何类型的对象列表)。(Dart支持顶级函数(例如main()),以及绑定到类或对象的函数(分别是静态和实例方法)。您还可以在函数内创建函数(嵌套函数或本地函数))。
这里简单介绍下:
Hello World
变量声明
数据类型
函数
流程控制
异常处理
类
泛型
异步操作
1. Hello World
和 Java 程序一样,dart程序也有一个入口函数 main ,把上面的程序保存为
hello_world.dart, 在命令行运行:安装之后需要配置环境变量
启动 dart 程序
2. 变量声明
变量声明关键字:
var、const、final、int、String、double(浮点型)、bool2.1 var 声明变量 —— 不指定类型
和 JavaScript 一样, 可以用
var声明变量不一样的是,
dart自带类型推断,一旦给变量赋值,它的类型就不可变了。2.2
int、String、double(浮点型)、bool声明变量——指定变量类型2.3
const和final声明常量3. 数据类型
3.1 dart提供基本的数据类型:
3.2 常用方法
3.2.1 number 取值范围:-2^53 to 2^53
3.2.2 string
${}引用表达式,或直接$引用标识符示例代码:
3.2.3 bool
Dart 是强 bool 类型检查,只有bool 类型的值是true 才被认为是true
3.2.4 List
声明 List 用 new List() 或者简单的赋值
下面是一些基本操作
3.2.5 map 散列表
基本操作
4. 函数
Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function。这意味着函数可以分配给变量或作为参数传递给其他函数。您也可以像调用函数一样调用Dart类的实例。
函数声明无需 function 关键字;
函数名前可标注函数返回类型,没有返回值的函数返回类型可设为void;
函数的参数可设定类型也可以不设
支持箭头函数
命名参数
调用命名参数的函数时,如果没有指定参数的名字,程序会崩溃报错。
参数默认值
为命名参数的某个参数指定默认值,这个参数就会变成可选参数。如上面的函数指定默认参数后可以这样调用:
5. 流程控制
...
这个流程控制语句使用和 JavaScript 没什么差异
6. 异常处理
try...catch...finaly
也跟 JavaScript 差不多。。。
7. 类 Class
7.1 类的定义
7.1.1 一个简单的类
还记得吗: dart中一切未赋值的变量值都是 null;
7.1.2 构造函数
通过创建一个与类同名的函数来声明构造函数;
dart 提供了语法糖,以更简单的方式来生成构造函数;
上面的代码只用一行代码就完成了构造函数,第一个参数,对应到name,第二个参数对应age;
命名构造函数(构造函数标识符)
上面的代码,构造函数有了一个名字(newBorn), 这样在初始化时更清楚使用了哪个类
7.2 继承
dart 的类通过 extends 关键字实现继承
调用父类构造函数
Garfield类继承了Cat类,并且在Garfield的构造函数里用SUPER关键字调用了Cat类的构造函数,重定向构造函数:有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。重定向构造函数的主体是空的,构造函数调用出现在冒号(:)之后。
上面定义了两个命名构造函数, small 调用了自身的构造函数,而自身又调用了dog的构造函数。
7.3 类中的函数
7.4 getter setter
默认的情况下类里定义的任何变量都是可以访问的,如
dog.name,变量的值也可以直接读写。但是有时候不希望直接读写而是通过gettersetter。dart里 是通过getset关键字实现的;7.5 抽象方法和抽象类
7.6 隐式接口
一个类通过
implements语句实现接口7.7 noSuchMethod
检测是否使用了不存在的变量或方法,可以重写
noSuchMethod方法,否则会抛出NoSuchMethodError这个异常;7.8 静态方法
在字段或方法前增加static关键字就变成了静态,如:
7.9 枚举类型Enum
使用enum关键字声明枚举类型:
枚举中的每个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。例如,第一个值具有索引0,第二个值具有索引1。
可以通过
.values获取枚举类中所有值的列表7.10 mixins 为类添加功能
mixins是一种在多层级结构类中重用代码的方法。
定义mixin:使用
mixin关键字创建一个没有构造函数的扩展类来实现一个mixin。使用mixin:通过
with关键字后跟多个类名来使用mixin;8. 泛型
Dart 支持泛型,在定义
List和Map类型时,可以手动指定其元素类型,类型一旦确定便不可更改,也不可向其中添加其他类型的变量。如:
同时,使用字面量定义变量时,Dart 也可以进行类型推断,如
var name = ['Seth', 'Kathy', 'Lars'],可以推断该 List 为List<String>()类型;不限定参数类型
如有一个类,管理一个数据,希望这个数据是任何类型。
9. 异步支持
Dart 支持异步操作。
使用异步首先要导入异步库
import: "dart/sync";异步操作(函数)有两种返回类型:
Future和Streams;Future基于观察者模式。类似于JavaScript里的Rx和Promise,如果熟悉这两个,就很容易理解Future。
简单来说,Future定义了未来将要发生的事,例如:未来我们会得到一个值。
Future 是泛型,Future,需要指定未来返回值的类型。如:
使用
async/await关键字执行异步操作,使用try,catch和finally来处理使用await的代码中的错误;用
async关键字修饰函数体就声明了该函数是异步函数;处理流 Stream
可用await for等待遍历stream的所有值,但要小心使用:
表达式的值必须具有Stream类型。执行过程如下:
要停止侦听流,您可以使用break或return语句,该语句将跳出for循环,并从流中取消订阅。
保证
await、await for要处在异步操作中参考文档: