chapter1 :简介
Dart是纯面向对象、基于类、使用可选类型、支持混入式继承以及Actor模式的并发编程语言。
1.关注对象的行为而非他的内部实现:
(1) Dart 的类型基于接口,而不是类. 作为一项原则,任意 类 都隐含了一个接口,能够被其它类实现.不管其他类是否使用了同样底层的实现
(2) Dart 没有final方法,部分内置的操作符除外.
(3) Dart 把对象进行了抽象封装, 以确保所有外部操作都通过存取方法来改变对象的状态.
(4) Dart 的构造函数允许对对象进行缓存,或者从子类型创建实例,因此使用构造函数并不意味着绑定了一个具体的实现.
Dart中的整数没有32位或64位可代表的最大值的限制,唯一能够限制其大小的是可用内存的大小.
但部分情况除外,比如:
👍在dart编译为javascript的时候,所有的数字都会变成javascript的数字,而js中只含有数字类型,并无整数类型,即使用浮点数来表示整数,并有大小的限制.
初见Dart语法糖
- 我们先来看一下一个class
// 这是一个叫Point的Class
class Point{
var x, y;
// 形参 a, b 将会接受具体实参的值
// 此后 a, b 的值将会被赋值给 Point 中的x, y
Point(a, b) {
x = a;
y = b;
}
}
Point 是一个最基础的类, 他有两个实例变量(或字段) : x与y.
要创建一个Point 类 的 实例 , 我们可以使用 new 表达式 来调用他的构造函数.
变量x, y 的值是由构造函数的实际参数来设置,而构造函数是由 new 调用的.
Dart 为此提供了一种特殊的语法糖:
class Point{
var x , y;
Point(this.x, this.y)
}
👍 this的指向其实很容易理解, 此时此刻是谁在调用,那么this指向的就是谁.
于是此处的this.x 自然也很好区分赋值给谁了.
注意: 在我们需要使用到某一些库的时候,需要先 import 其.
👍 Dart代码用库作为模块化的基本单元.每一个库都定义了一个命名空间,此命名空间包含所有在库中声明的实体的名称,其他库的实体也可以被导入进来.而Dart 核心库 中也声明了一些实体, 这些实体都已经被隐含地导入到所有的Dart库中了.
EG: 我们现在需要导入一个并不在核心库中的实体 — sqrt() ,它属于math库,请看:
// 与上述point类有关, 初学不明白具体意思,日后填坑
library points;
// 在这里盗入 math 库,就像python
import 'dart:math';
class Point{
var x , y;
Point(this.x , this.y);
static distance(p1 , p2){
// 在这里就可以正确使用 math 库 中的实体sqrt()了
return sqrt( 3 * 3 + 4 * 4);
}
}
于是我们自己申明的point库, 现在就可以正常使用sqrt()了,任意其他库,在成功导入Point库 后,也可以使用我们定义的 point类.
👍👍 import 后面跟着的是一个字符串’dart:math’.导入指向的都是用字符串表示的统一资源标至符(URI),编译器会通过指定的URI去找对应的库.
👍需要注意的点:
- 上面的demo中,我们看到了static,他表示Dart中的静态成员
- static 关键字用来实现类级别的变量和函数
- 静态方法不能访问非静态成员,非静态方法可以访问静态成员
chapter2 :对象、接口、类与mixin
一、属性访问器( )函数setter和getter
在Dart类的属性中有一种为了方便访问它的值特殊函数,那就是setter,getter属性访问器函数。实际上,在dart中每个实例属性始终有与之对应的setter,getter函数(若是final修饰只读属性只有getter函数, 而可变属性则有setter,getter两种函数)。而在给实例属性赋值或获取值时,实际上内部都是对setter和getter函数的调用。
1、属性访问器函数setter
setter函数名前面添加前缀set, 并只接收一个参数。
setter调用语法于传统的变量赋值是一样的。
如果一个实例属性是可变的,那么一个setter属性访问器函数就会为它自动定义,所有实例属性的赋值实际上都是对setter函数的调用。
👍get 有点类似于计算属性,其对一个属性进行操作;
👍set 亦是对 属性进行操作,但在为其赋值的时候,却没有使用圆括号进行传参,而是直接使用等号进行赋值。
class Rectangle {
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
set right(num value) => left = value - width;//使用set作为前缀,只接收一个参数value
set bottom(num value) => top = value - height;//使用set作为前缀,只接收一个参数value
get square => left * top ;
}
main() {
var rect = Rectangle(3, 4, 20, 15);
rect.right = 15;//调用setter函数时,可以直接使用类似属性赋值方式调用right函数。
rect.bottom = 12;//调用setter函数时,可以直接使用类似属性赋值方式调用bottom函数。
print(rect.square);
}
2.8 接口
Dart中没有接口的存在,因为其不是必要的,我们可以通过定义一个抽象类来描述所需的接口。
abstract class CartesianPoint{
get x;
get y;
}
abstract class PolarPoint{
get rho;
get theta;
}
// 尽管没有了接口声明, 泪也可以使他的实例实现特定的接口
class Point implements CartesianPoint , PolarPoint{
// 这里是Point 类的实现代码
}
上述代码 Point 类并不是 CartesianPoint 的子类,他没有继承CartesianPoint (或者 PolarPoint )的任何成员。implements的目的是在接口间建立预期的关联, 而不是实现共享实现。
我们可以使用 is 来检查对象的类是否明确地实现了某个接口(直接或间接)
5 is int; // true
'abc' is string; // true
10 is string; //false
Point.toString() is String; // true
Point is CartesianPoint; // true
2.10 noSuchMethod()
Dart 中的计算都是围绕对象方法的调用。如果调用了一个不存在的方法,则默认的行为会抛出一个noSuchMethodError 错误,但是并非总是如此。
当调用一个实例中不存在的方法时,Dart运行时会调用当前对象的noSuchMethod()方法。因为Object类noSuchMethod()方法的实现就是抛出noSuchMethodError错误,所以我们通常会看到这个熟悉的行为。但是优点在于,noSuchMethod()方法可以被重写。
class Proxy{
final forwardee;
Proxy(this.forwardee);
noSuchMethod(inv){
return runMethod(forwardee,inv);
}
}
注意:
noSuchMethod() 的参数是 Invocation类的一个实例,他是定义在核心库中的一个特殊类型,用于描述方法的调用。一个Invocation反映了原始的调用,描述了我们是原图调用方法的名称、传递的参数以及一些其他细节。
2.11 常量对象与字段
常量的值可以提前计算,只需一次,无需重新计算。Dart中常量是规范化的,一个给定的值只会产生一份常量。
const与final
我们一般对于常量使用 const 与 final 定义;
两者的差别在于: const 需要立即对对象进行初始化,而final可以延后初始化(可能表达的意思有误)。
因为时常会出现这种情况: 我们需要用到形参里的数据进行运算,这个数据一定是一个常量,但我们并不清楚他具体的值,在这种情况下使用const就不可取了,因为const是需要立即初始化的,于是final就可以在此处被我们使用。
2.12 类方法
2.15 mixin
在Dart 中是没有多继承的,我们如果想实现类似多继承的需求,可以使用mixin(他并不是多继承,仅仅是帮我们实现了这个功能)。下面记录的是Dart2.x版本的 mixin 功能。
- 作为mixin的类只能继承自Object,不可以继承自其他类。
- 作为mixin的类 不能拥有构造函数
- 一个类可以mixin多个类,若多个类中有同名函数,则后mixin类的函数会覆盖前面的同名函数
- mixin 不是继承也不是接口,而是一种新的特性。
class Mixa {
String strA = "我是A的string";
void funA() {
print("被mixin的类只能继承自Object");
print("被mixin的类不能拥有构造函数");
}
}
class Mixb {
String strB = "我是B的string";
}
class MixExted extends Mixa {
MixExted(String name) {
print('被 mixin 的类无法拥有构造函数,但被 extends 的类可以');
print(name);
}
void MixExtedPrint() {
print("继承自Mixa的MixExted方法");
}
}
class mixC extends MixExted with Mixa, Mixb {
mixC(String name) : super(name);
}
void main() {
mixC mixc = mixC('我是mixC');
print(mixc.strA);
print(mixc.strB);
mixc.MixExtedPrint();
}
常用的APi 总结
数字篇 ( num类型 )
void main() {
// parse();
// 用于将字符串类型转换成num类型,不会修改源数据
// 如果传递除数字以外的任何值,则解析函数抛出 FormatException 如: '12Aaa'
print(num.parse('12') + 15); // 27
print(num.parse('10.91')); // 10.91
int n = 880;
print(n.hashCode); // 输出数字的哈希值
print(n.isFinite); // 如果数字不是NaN或正无穷大或负无穷大,则该属性返回布尔值true。
print(n.isNegative); // 若数字为负数,即可返回true
print(n.sign); // 数字为负数 则返回-1;数字为 0 ,则返回 0;数字正数,则返回1
print(n.isEven); // 数字为偶数,返回true
print(n.isOdd); // 数字为奇数,返回true
print(n.abs()); // 返回数字绝对值
print(n.ceil()); // 针对小数执行, 返回该数的上一个整数 ; [注意分辨n的正负,-1.2 返回的是-1;1.2 返回的是2]
print(n.compareTo(12)); // 0:值相等。 n > 比较值 返回 :1。n < 比较值 返回 -1
num a = 5.97777;
print(a.toInt()); // 取整(不进行四舍五入)
print(a.toString().runtimeType); // 不修改源数据
print(a.truncate()); // 返回不带小数点的 整型
}
字符串篇 ( String类型 )
void main(List<String> args) {
String str = ' hello ';
print(str.isEmpty); // 判断字符串长度是否为0,是则返回true,否则为false
print(str.length); // 返回长度
print(str.toLowerCase()); // 转为小写
print(str.toUpperCase()); // 转为大写
print(str.trim()); // 去除左右所有空格
print(str.compareTo('haiho'));
// 返回表示两个字符串之间关系的整数。
//字符串相等返回 0。
//当第一个字符串大于第二个字符串时 返回1
//当第一个字符串小于第二个字符串时 返回-1
print(str.replaceAll('ll', 'cc')); // 用给定值替换与指定模式匹配的所有子字符串
print(str.split('l')); // 在指定分隔符的匹配处拆分字符串并返回子字符串列表。
print(str.substring(3)); // 根据索引值,返回一个字符串 (3)=> (0,3) 与js一样
int a = 5;
print(a.toString()); // 返回对象的字符串表示形式
print(str.codeUnitAt(0));// 返回给定索引处的16位UTF-16代码单元。
}
列表篇 ( List类型 )
void main(List<String> args) {
List<int> lst = [10, 20, 25, 19];
lst.add(123);
print(lst);
lst.replaceRange(0, 3, [11, 23, 24]);
// 将lst列表的前三项 分别替换为: 11,23,24
print(lst.first); // 此属性返回列表中的第一个元素
print(lst.last); // 此属性返回列表中的最后一个元素
print(lst.isEmpty); // 判断是否为空
print(lst.length); // 打印列表长度
print(lst.reversed); // 反转列表
// print(lst.single); //检查列表是否只有一个元素并返回它 否则报错
lst.remove(10); // print(lst); // remove()函数删除列表中第一次出现的指定项
print(lst.removeLast()); // 移除列表的最后一个数据,操作将修改源数据
print(lst);
}