Dart语法样式: https://www.dartlang.org/guides/language/effective-dart/style
语法:https://www.dartlang.org/guides/language/language-tour

概览

  • 重要概念
  • 关键词
  • 注释
  • 变量
  • 内置类型
  • 函数
  • 操作符
  • 流程
  • 异常
  • 泛型
  • 异步
  • 发电机
  • 可调用的类
  • 分离
  • 类型定义
  • 元数据

Dart是一种具有类和基于mixin的继承的面向对象语言。每个对象都是一个类的实例,所有类都来自Object
基于Mixin的继承意味着虽然每个类(除了Object)只有一个超类,但是类体可以在多个类层次结构中重用。

特点:当最左边的操作数为null时,使用?.而不是.避免异常:

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class {
num x,y; // 原始写法
Point(num x, num y){
// 该this关键字是指当前实例。
this.x = x;
this.y = y;
}*/ // 使用Dart语法糖
// 在构造体运行之前,为x,y设置语法糖。
Point(this.x, this.y); }

默认构造函数

如果未声明构造函数,则会为您提供默认构造函数。默认构造函数没有参数,并在超类中调用无参数构造函数。

构造函数不是继承的

子类不从其超类继承构造函数。没有声明构造函数的子类只有默认(无参数,无名称)构造函数。

命名构造函数(多构造函数)

1
2
3
4
5
6
7
8
// 命名构造函数:origin
Point.origin(){
x = 8;
y = 9;
} // 命名构造函数:withVal
Point.withVal(this.x, this.y);

注意:构造函数不是继承的,这意味着超类的命名构造函数不会被子类继承。如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数。

一个完整的多构造函数写法:

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
class {

  num x,y;

  // 原始写法
Point(num x, num y){
// 该this关键字是指当前实例。
this.x = x;
this.y = y;
}*/ // 使用Dart语法糖
// 在构造体运行之前,为x,y设置语法糖。
Point(this.x, this.y); // 命名构造函数:origin
Point.origin(){
x = 8;
y = 9;
} // 命名构造函数:withVal
Point.withVal(this.x, this.y); }

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void classAboutMethod(){

	var pointOrigin = Point(34,67);
print(pointOrigin.x);
print(pointOrigin.y); var pointAbout = Point.origin();
print(pointAbout.x);
print(pointAbout.y); var pointAboutVal = Point.withVal(11, 21);
print(pointAboutVal.x);
print(pointAboutVal.y);
}

结果为:

1
2
3
4
5
6
34
67
8
9
11
21

调用非默认的超类构造函数

执行顺序如下:

  • 初始化列表
  • 超类的无参数构造函数
  • 主类的无参数构造函数

初始化列表

重定向构造函数

有时构造函数的唯一目的是重定向同一个类中的另一个构造函数重定向构造函数主体是空的,构造函数调用出现在冒号(:)之后。

1
2
3
4
5
6
7
8
9
class {

  num x,y;

  Point(this.x, this.y);

  Point.alongX(num x) : this(x,0);

}

调用:

1
2
3
var pointAlongX = Point.alongX(11);
print(pointAlongX.x);
print(pointAlongX.y);

结果为:

1
2
11
0

常量构造函数

如果你想使你的类生成永远不会更改的对象,则可以使这些对象成为编译时常量。为此,请 定义 const构造函数确保 所有实例变量都是final

1
2
3
4
5
6
7
class ImmutablePoint {
static final ImmutablePoint origin = const ImmutablePoint(0, 0); final num x, y; const ImmutablePoint(this.x, this.y);
}

工厂建设者

在不需要总是创建新的实例的情况下可以使用 factory 关键字,例如下面这个例子表示:从缓存中返回对象的构造函数:

注意:工厂构造函数无权访问this。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class {

  num x,y;

  Point.alongX(num x) : this(x,0);

  static final Map<String, Point> _cache = Map<String, Point>{};

  factory Point.name(String name){
if (_cache.containsKey(name)) {
return _cache[name];
}else {
final point = Point.alongX(9);
_cache[name] = point;
return point;
}
}
}

调用:

1
2
3
4
5
6
7
var pointName = Point.name('Alice');
var pointName2 = Point.name('Alice');
var pointName3 = Point.name('Bob');
print(pointName.hashCode);
print(pointName2.hashCode);
print(pointName3.hashCode);
assert(pointName == pointName2);

结果:

1
2
3
477440163
477440163
461006651

使用class成员

  • 使用 . 来引用实例变量或方法
1
2
3
var pointOrigin = Point(34,67);
print(pointOrigin.x);
print(pointOrigin.y);
  • 最左边的操作数为null时,使用 ?. 而不是 . 避免异常:
1
2
3
4
5
6
7
8
9
// 如果pointAbout不为空,那么设置x = 4;
pointAbout?.x = 4;
print('pointAbout.x is ${pointAbout.x}');
// 结果:pointAbout.x is 4 pointAbout = null;
pointAbout?.x = 4;
//print('pointAbout.x is ${pointAbout.x}');
// 结果:抛出异常

使用构造函数

一般情况

1
2
3
4
5
6
7
var pointOrigin = Point(34,67);
print(pointOrigin.x);
print(pointOrigin.y); var pointAbout = Point.origin();
print(pointAbout.x);
print(pointAbout.y);

注意:在Dart2中,new是可选关键字。

常量构造函数

有些类提供常量构造函数。要使用常量构造函数创建编译时常量,请将const关键字放在构造函数名称之前

1
var p = const ImmutablePoint(2, 2);

如果构造2个相同编译时常量,那么结果是:产生同一个规范的实例:

1
2
3
4
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1); assert(identical(a, b)); // They are the same instance!

在常量上下文中,您可以省略const构造函数或文字之前的内容。例如,查看此代码,该代码创建一个const映射:

1
2
3
4
const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

那么,除了第一次出现的const外其他所有的const关键字都可以省略。简写为:

1
2
3
4
5
// Only one const, which establishes the constant context.
const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

如果常量构造函数在常量上下文之外并且在没有const的情况下调用,则会创建一个常量对象:

1
2
3
4
var a = const ImmutablePoint(1, 1); // Creates a constant
var b = ImmutablePoint(1, 1); // Does NOT create a constant assert(!identical(a, b)); // NOT the same instance!

获取对象的类型

要在运行时获取对象的类型,可以使用ObjectruntimeType属性,该属性返回一个Type对象

1
2
var pointAboutVal = Point.withVal(11, 21);
print('the type of pointAboutVal is ${pointAboutVal.runtimeType}');

结果为:

1
the type of pointAboutVal is Point

实例变量

以下是 声明 实例变量的方法:

1
2
3
4
5
class  {
num x; // Declare instance variable x, initially null.
num y; // Declare y, initially null.
num z = 0; // Declare z, initially 0.
}

所有未初始化的实例变量都具有该值null

所有实例变量都生成一个隐式getter方法。非final实例变量也会生成隐式setter方法。有关详细信息,请参阅Getters和setter。

1
2
3
4
5
6
7
8
9
10
11
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.
}

如果初始化声明它的实例变量(而不是构造函数或方法),则在创建实例时设置该值,该实例在构造函数及其初始化列表执行之前。

方法

方法是为对象提供行为的函数。

实例方法

对象的实例方法可以访问实例变量和this。

getters and setters

抽象方法

实例、getter和setter方法可以是抽象的,定义一个接口,但将其实现留给其他类。抽象方法只能存在于抽象类中。

1
2
3
4
5
6
7
8
9
10
11
abstract class Doer {
大专栏  Dart-Tour2-类"line"> // Define instance variables and methods... void doSomething(); // Define an abstract method.
} class EffectiveDoer extends Doer {
void doSomething() {
// Provide an implementation, so the method is not abstract here...
}
}

抽象类(abstract)

使用abstract修饰符定义抽象类 - 无法实例化的类。抽象类对于定义接口非常有用,通常还有一些实现。如果希望抽象类看起来是可实例化的,请定义工厂构造函数

1
2
3
4
5
abstract class Doer {
// Define instance variables and methods... void doSomething(); // Define an abstract method.
}

DartJava 关于 抽象类 的区别:

  • Dart:由abstract关键字修饰的类就是抽象类,由关键字决定。
  • Java:只要一个类中有未实现的方法,这个方法就是抽象类,由方法决定。

隐式接口(interfaces)

  • 每个类隐式的定义了一个接口,含有类的所有实例和它实现的所有接口。如果你想创建一个支持类 B 的 API 的类 A,但又不想继承类 B ,那么,类 A 应该实现类 B 的接口。

  • 一个类实现一个或更多接口通过用 implements 子句声明,然后提供 API 接口要求。例如

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
// 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()));
}

这里是具体说明一个类实现多个接口的例子:

1
2
3
class Point implements Comparable, Location {
// ...
}

特点:
这里的interface接口和java不同在于:不需要定义interface任何class都可以被implements

继承类(extends)

同Java

重写成员(@override)

同Java

注意:要在类型安全的代码中缩小 方法参数实例变量类型,可以使用covariant关键字。

例子:

1
2
3
4
5
6
7
8
9
class Animal {
void chase(Animal x) { ... }
} class Mouse extends Animal { ... } class Cat extends Animal {
void chase(covariant Mouse x) { ... }
}

虽然此示例显示covariant子类型中使用,但covariant关键字可以放在超类子类方法中。通常,超类方法是放置它的最佳位置。该covariant关键字适用于单个参数,并且在setter和字段上也受支持。

重写操作符

您可以覆盖下表中显示的运算符。

说明:表达e1 != e2!(e1 == e2)的语法糖。

一个覆盖+-运算符的类的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Vector{
final x,y; Vector(this.x, this.y); Vector operator +(Vector v) => Vector(x + v.x,y + v.y);
Vector operator -(Vector v) => Vector(x - v.x,y - v.y); } final v = Vector(2,2);
print('x is ${v.x}, y is ${v.y}'); final w = Vector(4,5);
print('x is ${w.x}, y is ${w.y}'); var vw = v + w;
print('x is ${vw.x}, y is ${vw.y}');

结果为:

1
2
3
x is 2, y is 2
x is 4, y is 5
x is 6, y is 7

noSuchMethod()

可以通过重写noSuchMethod()可以发现或者对在代码中尝试使用不存在的方法或者实例变量作出反应。

1
2
3
4
5
6
7
8
9
class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError. void noSuchMethod(Invocation invocation) {
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}

你不能调用未实现的方法,除非以下一个是真实的:

  • 接收器具有静态类型dynamic。

  • 接收器有一个静态类型,它定义了未实现的方法(抽象是OK),接收器的动态类型的实现与类noSuchMethod() 中的实现不同Object。

枚举类型

枚举类型(通常称为枚举或枚举)是一种特殊类,用于表示固定数量常量值

使用enum关键字声明枚举类型:

1
enum Color { red, green, black }

枚举中的每个值都有一个index,从0开始。如:

1
assert(Color.black.index == 2);

要获取枚举中所有值的列表,请使用枚举values常量。如:

1
2
3
4
List<Color> colors = Color.values;
for (var x in colors) {
print('当前的索引为: ${x.index} ,对应着的值为:${x}');
}

结果为:

1
2
3
当前的索引为: 0 ,对应着的值为:Color.red
当前的索引为: 1 ,对应着的值为:Color.blue
当前的索引为: 2 ,对应着的值为:Color.black

switch用法

1
2
3
4
5
6
7
8
9
10
11
12
13
void doSwitch() {
var colorSingel = Color.black;
switch (colorSingel) {
case Color.black:
break;
case Color.blue:
break;
case Color.red:
break;
default:
print('');
}
}

向类添加功能:mixin

mixins是一种在多个类层次结构重用类代码的方法。可以简单的理解为: mixin修饰的类中定义了多个类公用变量方法

mix混合的意思in在……里面。那么mixin可以理解为:可以混合在指定类里面公用代码块。用mixin关键字代替class关键字来实现一个可扩展的Object类,且无需声明构造函数 :

mixin本身可以抽象的,可以定义各种方法属性,也可以是抽象的,等后续类去实现。

mixin使用

要使用 mixin,请使用with关键字后跟一个或多个 mixin关键字修饰的类。以下示例显示了使用有mixins修饰的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mixin TestMixin {
void test() {
print('test');
}
int testInt = 1;
void test2();
} class Test with TestMixin { test2() {
print('test2');
}
} void main() {
Test().test(); // test
print(Test().testInt); // 1
Test().test2(); // test2
}

注意:mixinDart 2.1中引入的对关键字的支持。

mixin与on关键字:

要指定只有某些类型可以使用mixin——使用on来指定所需的超类,这样你的mixin可以调用一个它自身没有定义的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class BaseObject {
void method() {
print('call method');
}
}
mixin TestMixin on BaseObject{
void test() {
print('test');
}
int testInt = 1;
void test2() {
method();
}
} class Test extends BaseObject with TestMixin {
} void main() {
Test().test(); // test
print(Test().testInt); // 1
Test().test2(); // call method
}

当使用on关键字后,则表示该mixin修饰的类只能在那个类的子类使用了。

多个mixin

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
32
33
34
35
36
37
38
39
40
41
42
mixin TestMixin1 on BaseContext{

  var intValue = 1;

  void mix1() => print('this is from textMixin1');

  void printAnother() => sayHello();

}

mixin TestMixin2 on BaseContext{
var intValue = 2;
void mix2() => print('this is from testMixin2'); void printBye() => sayGoodbye();
} class BaseContext{ void sayHello() => print("BaseContext say hello"); void sayGoodbye() => print('BaseContext say byebye'); } class TestClass extends BaseContext with TestMixin1,TestMixin2{
@override
void mix2() {
// TODO: implement mix2
super.mix2();
print('this msg is from TestClass!');
}
} void main(){
TestClass().mix2(); // this is from testMixin2 this msg is from TestClass!
TestClass().mix1(); // this is from textMixin1
TestClass().sayGoodbye(); // BaseContext say byebye
TestClass().printAnother(); // BaseContext say hello
TestClass().printBye(); // BaseContext say byebye
print(TestClass().intValue); // 2
}

TestMixin1TestMixin2中都声明了一个intValue变量,但是值不同。在class TestClass extends BaseContext with TestMixin1,TestMixin2的顺序中,得到的结果是:

1
2

即:TestMixin2 中初始化的值。

那么改变一下with的顺序呢?class TestClass extends BaseContext with TestMixin2,TestMixin1,结果是:

1
1

由此可见:取值的是最后一个with的类中的值。

类变量和方法

使用static关键字实现类范围的变量和方法。

静态变量

静态变量(类变量)对于类范围状态常量很有用:

1
2
3
4
5
6
7
8
class Queue {
static const initialCapacity = 16;
// ···
} void main() {
assert(Queue.initialCapacity == 16);
}

注意:

  • 静态变量在使用之前不会初始化。
  • 遵循样式指南建议,优先使用lowerCamelCase作为常量名称

静态方法

1
2
3
4
5
6
7
8
9
10
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);
}
}

注意

  • 对于常用或广泛使用的实用程序和功能,请考虑使用顶级函数而不是静态方法。

您可以使用静态方法作为编译时常量。例如,您可以将静态方法作为参数传递给常量构造函数。

Dart-Tour2-类的更多相关文章

  1. Dart 面向对象 类 方法

    Dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,并且所有的类都是Object的子类. 面向对象编程(OOP)的三个基本特征是:封装.继承.多态 封装:封装是对象和类概念的主要特性. ...

  2. [dart学习]第七篇:类(构造函数)

    前言:楼主平时基本没有使用过异常处理,所以对异常的认知可能不够准确,这里就不翻译异常的相关内容了,大家可以去官网自行阅读介绍,地址 https://dart.dev/guides/language/l ...

  3. Dart 语言简易教程系列

    google Fuchsia系统 及 dart语言简介 在 InteIIiJ IDEA 中搭建 Dart 的开发环境 Dart Linux 开发环境搭建 Dart 语言简易教程(一) Dart 语言简 ...

  4. Dart编程语言入门

    Dart基础入门语法介绍,详细说明可以查看相关视频<Dart编程语言入门>. 变量与常量 变量 1.使用 var 声明变量,默认值为 null var a;//null a = 10; 2 ...

  5. Dart和JavaScript对比小结

    作为一名web前端来入门dart,新语言和我们熟悉的js有所差异,写dart的过程中容易受到原有思维的影响,这里把dart和js做一个对比总结,方便查找和熟悉. 变量声明 var 关键字 dart和j ...

  6. Dart 和 Flutter 使用json_annotation和json_serializable来处理json数据教程

    在学习fultter的时候突然想到如何去处理从服务器获取的json或者将app中的对象数据转换成json上传给服务器 于是研究一下dart对json数据的处理 首先需要依赖下面的第三方库(这里要强调下 ...

  7. 【dart学习】-- Dart之类和对象

    一,概述 类(Class)是面向对象程序设计,实现信息封装的基础.类是一种用户定义的类型.每个类包含数据说明和一组操作数据或传递消息的函数.类的实例称为对象. Dart的类与其它语言都有很大的区别,比 ...

  8. Flutter 使用json_model解析json生成dart文件

    一.json_serializable使用步骤 1.集成json_serializable pubspec.yaml 添加以下依赖 dependencies: json_annotation: ^2. ...

  9. flutter--Dart基础语法(三)类和对象、泛型、库

    一.前言 Flutter 是 Google 开源的 UI 工具包,帮助开发者通过一套代码库高效构建多平台精美应用,Flutter 开源.免费,拥有宽松的开源协议,支持移动.Web.桌面和嵌入式平台. ...

  10. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

随机推荐

  1. fread 和fgets 函数的使用

    两个函数都是对FILE *fp 文件进行读取信息,fgets是每次读取一行,fread是一下子读完所有的文件内容. //一.fread的使用 FILE *fp; int nread; ] fp = f ...

  2. 7.docker file 语法

    详细文档 : https://docs.docker.com/engine/reference/builder/ 1. FROM   尽量使用官方的 image 作为 base image FROM ...

  3. 17.3.13---sys.argv[]用法

    1------sys.argv[]是用来获取命令行参数, sys.argv[0]表示代码本身文件路径,因此要从第二个即sys.argv[1]开始去参数 例如创建一个文件: import sys pri ...

  4. debian下通过scp 上传下载文件

    1.上传本地文件到服务器 scp /path/filename username@servername:/path/ 2.从服务器上下载文件 scp username@servername:/path ...

  5. vue结合element实现自定义上传图片、文件

    参考了很多文献,感谢各位帖子,所以也想把自己遇到不会的东西分享出来,菜鸟一枚大家一进步!

  6. mysql_secure_installation 安全安装(用于生产环境设置)

    编译安装完mysql5.6,如果用于生产环境,最好执行mysql_secure_installation来做一些常规化安全设置. 需要提前将~mysql/bin加入环境变量 /apps/mysql// ...

  7. ofo小黄车做信息流!这到底算怎么回事?

    不得不说,现在ofo绝对处于商业处境和舆论的风口浪尖上.近段时间以来,ofo各种大动作实在是让业界和大众都"看不懂".但毋庸置疑的是,ofo的种种举措都是为了"自救&qu ...

  8. Java复习(五)接口与多态

    5.1接口 允许创建者规定方法的基本形式:方法名.参数列表以及返回类型,但不规定方法主体. 也可以包含基本数据类型的数据成员,但他们都默认为static和final 声明格式为 [接口修饰符]inte ...

  9. 量化投资_TB交易开拓者A函数和Q函数常见组合应用

    1 在交易开拓者当中,关于交易的做单方式一般分为:图表函数和A函数两类. 两类的主要区别为:如果采用图表函数的话,所有的交易内容都是以图表上面的信号为准,当前仓位运行的实际状态是没有的,但是可以显示交 ...

  10. day19-3个双下item方法

    #使用双下item方法来实现属性的增删改查: # 查:__getitem__ 增改:__setitem__ 删除: __delitem__ class Goods: def __init__(self ...