This commit is contained in:
结发受长生 2019-10-06 21:16:37 +08:00
parent 32acd76e27
commit 065883b1cb
2 changed files with 520 additions and 0 deletions

View File

@ -0,0 +1,228 @@
---
title: dart初见(1)
date: 2019-09-28 12:08:40
tags:
- dart
categories:
- dart
---
Flutter是谷歌推出的跨平台移动端开发框架
它使用dart这门小众语言作为开发语言
想到自己在移动端开发这块的技能还相对薄弱所以最近学习了一下这门语言为学习Flutter框架稍作准备
<!-- more -->
dart的代码语句末尾必须写分号
学习一门编程语言,当然要先了解这门语言的基础设施
### 变量与数据类型
dart语言有类型推导机制但仍然是强类型语言
未初始化的变量值均为null如果一个变量未在定义时被初始化那么它的类型就不会被确定
可以指向任意类型的对象
```dart
void main() {
var num1 = 10;
num1 = 'hello'; // 错误
print(num1);
var num2;
num2 = 10;
num2 = 'hello'; // 正确
print(num1);
}
```
`var`来定义变量会执行类型推导
也可以用`int`等类型名称直接声明变量类型,比如`int a = 10;`
#### 内置的数据类型
+ **数值型-Number** - 用`num`表示,包含`int``double`两种子类型,分别表示整数和浮点数
+ **字符串-String** - 用`String`表示
+ **布尔型-Boolean** - 用`bool`表示分为true和false
+ **列表-List** - 用`List`表示,用诸如 **\[10,'ab',15.9\]** 的形式声明一个列表(类似python)
前面加const表示不可变的List
+ **无序集合-Set** - 用`Set`表示,用诸如 **{10,'ab',15.9}** 的形式声明一个无序集合,集合中的元素是唯一的
+ **键值对-Map** - 用`Map`表示,用诸如 **{'a':10, 'b':20}** 的形式声明一个键值对的集合
+ Runes、Symbols
这些本质上都是dart内置的类比如int和double这两个类就是继承自num类的
#### final与const
用final修饰的变量必须在定义时将其初始化其值在初始化后不可改变const用来定义常量
它们的区别在于const比final更加严格。final只是要求变量在初始化后值不变但通过final我们无法在编译时运行之前知道这个变量的值
而const所修饰的是编译时常量我们在编译时就已经知道了它的值显然它的值也是不可改变的。
```dart
void main() {
final int m1 = 60;
final int m2 = func(); // 正确
const int n1 = 42;
const int n2 = func(); // 错误
}
int func() {
return 500;
}
```
上面的例子当中显然编译期是无法知道func函数的执行结果的所以无法用const变量接收其返回值
### 数值型操作
针对数值的运算符,大部分都和其他语言差不多
有差别的是多一个`~/`运算符,它表示取整的除法,直接使用`/`是保留小数部分的
`%`取余运算是不取整的
常用属性
+ `isNaN` - 0/0的运算会得到一个NaN可以用来做判断
+ `isEven` - 是否是偶数
+ `isOdd` - 是否是奇数
常用方法
+ `abs()` - 取绝对值
+ `round()` - 四舍五入
+ `floor()` - 向下取整
+ `ceil()` - 向上取整
+ `toInt()` - 转换为int类型
+ `toDouble()` - 转换为double类型
### 字符串操作
1. 使用单引号或双引号来表示字符串常量
2. 三个单引号或双引号可以表示多行字符串
3. 使用`r`创建原始raw字符串
前两种都很简单和js也类似
第三种的意思是是否对转义字符进行处理
```dart
String str1 = 'a\nb';
String str2 = r'a\nb';
print(str1); // a b
print(str2); // a\tb
```
第一个转义字符是起作用的,第二个则不会对转义字符进行处理
运算符
+ `+` - 字符串拼接(注意字符串不能与非字符串类型的常量或变量进行拼接)
+ `*` - 后面跟的是次数,表示把该字符串重复若干次
+ `==` - 判断是否相同
+ `[]` - 获取字符串指定索引位置的字符(从0开始)
插值表达式`${expression}`
```dart
int a = 10;
int b = 20;
print('a=$a'); // 如果只是一个变量 也可以不写大括号
print('a+b=${a+b}');
```
常用属性
+ `length` - 字符串长度
+ `isEmpty` - 是否是空串
+ `isNotEmpty` - 是否不是空串
常用方法
+ `contains(str)`,`subString(start,end)` - 是否包含某个子串,取子串(end不传则截取到末尾)
+ `startWith(str)`,`endsWith(str)` - 是否以某个字符串开头/结尾
+ `indexOf(str)`,`lastIndexOf(str)` - 子串第一次/最后一次出现的位置
+ `toUpperCase()`,`toLowerCase()` - 转换为大写/小写
+ `trim()`,`trimLeft()`,`trimRight()` - 去除首/尾的空白字符
+ `split(str)` - 分割字符串得到一个List对象
+ `replaceAll(form,str)` - 正则替换
replace有一系列的方法
第一个参数可以是字符串也可以是正则对象
```dart
String str1 = 'ab123cd45';
RegExp numReg = new RegExp(r'\d+'); // 也可以写 '\\d+'
print(str1.replaceAll(numReg, '..')); // ab..cd..
```
### List操作
一个List在定义之后可以使用类似数组操作的方式用`[]`获取指定下标的元素以及修改指定元素
使用`length`属性获取List的长度
但是不能像js那样对越界的下标直接赋值
常用方法
+ `add(value)`,`insert(index,value)` - 添加元素/在指定位置添加元素
+ `remove(value)`,`removeAt(index)` - 移除指定元素/指定位置的元素
+ `indexOf(value)`,`lastIndexOf(value)` - 查找元素第一次/最后一次出现的位置,找不到返回-1
+ `sort(func)` - 以指定规则排序
> dart同样支持函数式编程
sort就需要传入一个函数对象这个函数需要返回一个整数
正数表示大于负数表示小于0表示等于
```dart
List list1 = ['aa','b','cccc','ddd'];
list1.sort((a,b) => a.length.compareTo(b.length));//[b, aa, ddd, cccc]
```
+ `shuffle()` - 随机乱序
+ `asMap()` - 转换为下标为key元素为value的键值对集合
+ `forEach(func)` - 对List执行遍历(传入一个函数)
### Map操作
使用`[]`的方式获取或修改Map当中的元素
`length`可以获取Map的键值对数量
`keys``values`可以获取键和值的集合
常用方法
+ `isEmpty()`,`isNotEmpty()` - 判断是否(不)为空
+ `containsKey(key)`,`containsValue(value)` - 是否包含某个键/值
+ `remove(key)` - 按照key移除某个键值对
+ `forEach(func)` - 遍历Map
### dynamic与泛型
dart语言当中使用`dynamic`来表示动态类型
```dart
var a;
a = 10;
a = 'abc'; // a就相当于是dynamic类型的一个变量
// 也可以这样定义变量
dynamic b = 20;
b = 'cde';
```
对于集合类型可以指定泛型或者使用dynamic来表示任意类型
比如
```dart
Map<String, dynamic> map = new Map();
```
就表示这个Map的key必须是字符串value可以是任意类型
### 条件表达式与运算符
dart当中除了常规的赋值与三目运算符之外
还有`??`运算符以及`??=`赋值运算符
```dart
int a = 10;
a ??= 20;
print(a); // 10
int b;
int c = b ?? 30;
print(c); // 30
```
+ `??=` 代表为左值空的时候就执行赋值,否则就什么都不做
+ `expr1 ?? expr2` 代表判断expr1是否为null如果为null就取expr2的值否则就取expr1的值
### switch语句的差异
dart当中的switch与其他语言的用法基本一致
有一点差别就是
> 不是switch当中的最后一个case
其最后一个语句必须是下列关键字其中之一
`break`, `continue`, `rethrow`, `return` or `throw`
+ `continue`后面必须跟一个label的名称label必须是在这个switch当中某个位置指定的标签
```dart
void func(String name) {
switch(name) {
case 'Sookie' :
print(1);
continue label1;
case 'Alice' :
print(2);
break;
label1:
case 'Lily' :
print(3);
}
}
```
+ `rethrow`可以写在catch块当中代表在捕获异常的同时进行传播

View File

@ -0,0 +1,292 @@
---
title: dart初见(2)
date: 2019-10-06 21:08:37
tags:
- dart
categories:
- dart
---
### 函数相关
dart当中函数也是一个对象具备共同的抽象类`Function`
因为是抽象类所以不能直接用其执行new创建对象
<!-- more -->
#### 可选参数
dart在定义函数的时候可以在形参表的末尾添加可选参数
有命名参数和匿名参数两种形式
```dart
void main() {
func1('Sookie', c: true, b: 10);
func2('Sookie', 20, false);
}
// 命名可选参数
void func1(String a, {int b, bool c}) {
print('a=${a},b=${b},c=${c}');
}
// 匿名可选参数
void func2(String a, [int b = 100 ,bool c]) {
// 可以给可选参数指定默认值
print('a=${a},b=${b},c=${c}');
}
```
命名的可选参数因为传参时指定形参名称,所以就不会强制顺序的匹配了
可选参数的声明必须在形参表的末尾
#### 匿名函数和箭头函数
**匿名函数**
```
(参数1, 参数2 ...) {
函数体
}
```
匿名函数不能声明返回值类型,或者说它的返回值是任意类型的,相当于是`dynamic`
> dynamic并不算一种类型只是作为一个关键字表示动态类型
就像var也是关键字但是会执行类型推导
**箭头函数**
```
(参数1, 参数2 ...) => 返回值
```
箭头函数只能有一个表达式作为返回值,而不能有其他语句
函数对象都可以使用变量进行接收
#### 级联调用
dart当中使用`..`来实现级联调用
```dart
List list1 = [10,15,20];
list1..add(19)..remove(10);
// 相当于
List list2 = [10,15,20];
list2.add(19);
list2.remove(10);
```
### 面向对象
使用`class`关键字来声明一个类,创建对象时`new`关键字可以省略
dart中不支持函数重载
可以使用`.`来访问对象的成员
当然如果变量是null会报空指针的错误
可以判断是否为null
也可以使用`?.`操作符相当于自带判断是否为null如果是null就不执行调用
类如果实现了`call`函数,那么它的实例就可以直接当做函数来执行调用
```dart
void main() {
Demo demo = new Demo();
demo('hello');
}
class Demo{
void call(String msg) {
print(msg);
}
}
```
#### 计算属性
对于不是固定值,而是需要使用一些逻辑获得计算结果的情况
我们可以将其定义为类当中的一个函数,也可以使用计算属性
计算属性分为`get``set`两种
```dart
void main() {
Rectangle rect = new Rectangle();
rect.width = 10.9;
rect.height = 20.3;
print(rect.area); // 221.27
rect.area = 100;
print(rect.width); // 5.0
}
class Rectangle {
num width, height;
num get area {
return width * height;
}
void set area(num value) {
this.height = 20;
this.width = value / 20;
}
}
```
> 它本身当然是个函数,也可以使用箭头函数的写法
#### 构造函数
定义一个类时,如果不写构造函数,会默认提供一个无参的构造函数
支持匿名构造函数与命名构造函数两种
构造函数也不能被重载,如果要实现一个类有多个构造函数,就必须使用命名构造函数
```dart
class Person {
String name;
int age;
// 匿名构造函数
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 也可以写作
// Person(this.name, this.age);
// 命名构造函数
Person.withName(String name) {
this.name = name;
}
}
```
命名构造函数调用时写作 **new Person.withName('sookie')**
对于`final`修饰的类属性,想要在构造函数进行初始化,只能使用这种语法糖的形式来写
```dart
class Person {
final String name;
int age;
Person(this.name, this.age);
Person.withName(this.name);
// 下面的方式是报错的
// Person(String name, int age) {
// this.name = name;
// this.age = age;
// }
// 这种方式当然也报错
// Person.withName(String name) {
// this.name = name;
// }
}
```
##### 常量对象
```dart
void main() {
const Person p = const Person('Sookie', 18);
print(p.name);
}
class Person {
final String name;
final int age;
const Person(this.name, this.age);
}
```
##### 工厂构造方法
dart自带了工厂设计模式的实现工厂构造方法需要返回该类的实例对象
```dart
class Logger {
String name;
static final Map<String, Logger> _cache = new Map();
factory Logger(String name) {
if(!_cache.containsKey(name)) {
_cache[name] = new Logger(name);
}
return _cache[name];
}
}
```
#### 类型转换
使用`as`进行强制类型转换
使用`is``is!`来判断是否属于某种类型
```dart
dynamic a = 'abc';
if(a is String) {
print((a as String).toUpperCase());
}
```
如果不执行强制类型转换就不能直接调用String上的方法因为此时a还是动态类型
#### 继承
dart当中的继承与java基本类似
+ 使用`extends`关键字实现继承,只能单继承,具备多态特性
+ 子类会继承父类可见的成员,不会继承构造方法
+ 子类可以重写父类的方法(重写的方法上可以添加`@override`注解)
+ 所有类都有公共的基类`Object`
##### 构造函数
子类的构造函数会默认隐式调用父类无名无参的构造函数
如果父类当中没有则需要使用super显式调用
```dart
class Demo1{
String name;
Demo1(String name) {
print('Demo1:${name}');
}
Demo1.withName(String name) {
this.name = name;
}
}
class Demo2 extends Demo1 {
// 显式调用父类的匿名构造函数
Demo2(String name):super(name) {
print('Demo2:${name}');
}
// 显式调用父类的命名构造函数
Demo2.withName(String name):super.withName(name) {
this.name = name;
}
}
```
#### 抽象类与接口
抽象类使用`abstract`修饰跟Java基本一样可以定义抽象方法或者有具体实现的方法抽象方法并不需要再加abstract修饰
但是并不存在interface关键字
一个类本身就可以当做接口来使用
```dart
class Demo{
String name;
void test(String msg) {
print(msg);
}
}
// 如果作为接口使用,就必须重写所有的属性与方法
class Demo1 implements Demo {
@override
String name;
@override
void test(String msg) {
// TODO: implement test
}
}
```
当然这是非常冗余的,至少属性没什么好重写的
所以实际开发当中通常把抽象类当做以往意义上的接口来使用
#### Mixins
使用extends只能实现单继承Mixins就是多继承的一种实现方式
使一个类同时拥有多个类的成员
```dart
class A {
void a() {
print('A.a');
}
}
class B {
void b() {
print('B.b');
}
}
class C with A,B {
//这个类中同时具备A,B两个类的成员
}
// 如果类中不需要添加其他成员,也可以使用如下简写方式
class D = A with B;
```
如果A和B当中存在同名方法那么就是根据**with之后的声明顺序**
A在前B在后所以C中实际具备的是B当中的该方法
需要注意的是with后面跟的类
1. **不能**有显式声明的构造函数
2. **只能**直接继承自Object(可以省略 extends Object)
3. 可以使用implements实现接口
### 模块化
+ 可见性以`library`(库)为单位差不多可以理解为JavaScript当中的模块
+ 每一个dart文件就是一个库
+ 以`_`开头声明的类或者函数是在当前库当中私有的,即使其他库引入了该库,也无法在其他库中使用
+ 使用`import`来引入一个库文件
+ dart的sdk有自带的一套类库`dart.core`是默认被引入的