目录
本篇可随意转载!Update 2022.05.24
前言
Dart是Google设计用来统一前端开发的编程语言,是Flutter框架的默认编程语言。
代码在线调试:地址
本文要求读者有Java语言背景,因为本文只介绍了Dart跟Java不一样的特性,信息量非常大。
1. Dart语言特性
1.1 字面变量:
// 可用单/双引号,可用模板字符串:$xx打印变量
num aNumber = 1;
print('this is a $aNumber');
1.2 不固定类型变量:
var aNumber = 123;
dynamic b = '123';
未赋值变量默认是null。
1.3 常量:
const age = 18;
// 可以将运行时的值赋值给final变量
final age2 = DateTime.now();
1.4 数值类型:num int double
// 结果是3
print(3.8.toInt());
// 四舍五入
print(3.8.round());
// 保留4位小数
print(3.1415926.toStringAsFixed(4));
// 取余数=1
print(10.remainder(3));
// 数值比较,相同:0;大于:1;小于:-1
print(10.compareTo(12));
// 科学计数法: 1.00e+3
print(1000.toStringAsExponential(2));
// 非数字类型: NAN 如下:
var n = 0/0;
print(n.isNaN);
1.5 布尔类型
// 布尔值
bool a = true;
var flag;
// 下面报错,flag不包含null类型
if( flag ){
print('true');
}else{
print('false');
}
1.6 List类型
List alist = [];
// 限制List中的变量类型
List aIntList = <int>[];
List b = new List.empty(growable:true);
// 填充3个0
List c = new List.filled(3, 0);
// 扩展操作符
List d = [1, 2, 3];
List e = ['a', ...d];
// List长度,不用小括号
print(e.length);
// List判空,不用小括号
print(e.isEmpty);
// 删除指定下标元素
e.removeAt(1);
// 连接列表元素
List f = ['fuck', 'you'];
print(f.join('-'));
// 遍历列表操作 forEach() map() where() any() every() expand()
var numbers = [1, 2, 3];
List list = ['a', 'b', 'c'];
numbers.forEach((element){
print(element);
});
var newNumbers = numbers.map((e){
return e*e;
});
print(newNumbers);
bool isOdd(n) => n%2==1;
var oddNumbers = numbers.where((element) => isOdd(element));
print(oddNumbers);
print(numbers.any(isOdd));
print(numbers.every(isOdd));
var twoDim = [[1, 2], [3, 4]];
var flattened = twoDim.expand((element) => element).toList();
print(flattened);
1.7 Set类型
var set1 = {'a', 'b', 'c'};
var set2 = new Set();
set2.addAll(['c', 'd', 'e']);
// 求两个Set的交集
print(set1.intersection(set2));
// Set无法用下标访问元素
print(set1.first);
print(set1[1]);
// 求并集要求两个集合类型相同
print( set1.union(set2) );
1.8 Map类型
// 使用var, dynamic, Map声明类型都行
Map person = {
"name": "Alex",
"age": 20
};
// 增加元素
person.putIfAbsent('gender', ()=>'male');
print(person);
// 条件删除
person.removeWhere((key, value) => key == 'gender');
print(person);
1.9 其他类型
Runes
utf-32,参考网址: https://copychar.cc
Runes input = new Runes('\u{1f680}');
print(new String.fromCharCodes(input));
Symbol类型
var a = #abc;
var b = new Symbol('abc');
1.10 运算符
var a=21;
var b=5;
var c = a % b;
// 地板除
var d = a ~/ b;
print(c);
print(d);
print("$a与$b相除等于$d余数是$c");
1.11变量避空
int a = 6;
int b;
a??=10; //a为空则赋值,不为空则不赋值
b??=10;
print("$a---$b");
int c;
var d = c ?? 7; //c为空则赋值,不为空则不赋值
print("d=$d");
1.12 类型转换
String price = "199.9";
try{
double p = double.parse(price); //String类型转换double
print(p);
}catch(err){
print(err);
}
1.13 条件属性访问
var m;
print(m?.length); //此处返回null而不是抛出异常
1.14 级联访问
Set a = new Set();
a..add('1')..add('2')..remove('1');
2.Dart函数
2.1 函数本身也是对象
// 函数是对象 -->true
print( (){} is Object );
2.2匿名函数
var printNumber = () {
print("anonymous function, print a number");
};
2.3箭头函数
var list = [1, 2, 3];
list.forEach((element)=>{
print(element)
});
2.4立即执行函数
(() => print('self running'))();
2.5 闭包
函数里包含局部变量并嵌套子函数,并返回子函数。它可以让变量不占用全局作用域,且全局可访问。
void main() {
var fn = () {
int n = 0;
print("init n=$n");
return () {
n++;
print("return n=$n");
};
};
// n=1
fn()();
// n=1
fn()();
// runner为函数对象
var runner = fn();
// 执行函数对象返回n=1
runner();
// 再次执行函数对象返回n=2
runner();
}
2.6 函数可选参数
// 中括号
void userInfo(String name, [int age = 0 ]){
print('user name = ${name}, age=${age}');
}
2.7 函数命名参数
// 大括号
void userInfo(String name, {int age = 0}){
print('user name = ${name}, age=${age}');
}
void main() {
// 直接用名字+冒号
userInfo('Alex', age:30);
}
2.8函数作为参数
var func = (value)=>print('this is ${value}');
List list = [1,2,3];
list.forEach(func);
2.9 异步函数 async await
3. 类
实例化类的new关键字可以省略。
3.1 普通构造函数
class Point{
...
// 无body构造函数
Point(this.x, this.y);
}
3.2 命名构造函数
Point.anyNamexxx({x:1, y:1}){
this.x = x;
this.y = y;
}
}
3.3常量构造函数 const +构造函数
3.4 工厂构造函数 factory+构造函数
3.5 访问修饰符
dart中没有private,protected,public,默认就是public,私有的变量和方法以_开头:
class A{
int _aaa = 0;
void _doxx(){
print('_aaa');
}
}
注意: main和class在一个文件的时候,不能保证私有,类需要单独用文件存储。
3.6 get和set关键字
class Sharp{
num r = 1;
num get area{
return r*r;
}
set setR(num r){
this.r = r;
}
}
void main() {
Sharp sharp = new Sharp();
print(sharp.area);
sharp.setR = 10;
print(sharp.area);
}
3.7 初始化列表
class Rect {
int x;
int y;
Rect(): x = 2, y = 3 {
print('x=${x}, y=${y}');
}
// 初始化列表的特殊用法- 重定向构造函数
Rect.origin(int x, int y) : this(x, y);
}
4. 接口和Mixin
4.1 接口
Dart中的接口就是一个abstract class(也可以用普通类),不需要interface关键字做修饰。类通过implements关键字实现接口。
abstract class Processor{
String cores;
arch(String name);
}
class Phone implements Processor {
@Override
String cores;
@Override
arch(String name) {
print('手机芯片: $name');
}
}
4.2 Mixin
使用类声明Mixin
class A {
void printA(){
print('A');
}
}
使用类声明的Mixin,不能继承除了Object以外的任何类,也不能有构造函数
使用Mixin关键字
mixin B {
void printB(){
print('B');
}
}
普通类通过with来使用Mixin
class CommonClass with A, B{
}
void main(){
var c = new CommonClass();
c.printA();
c.printB();
}
5. 泛型
泛型分为:泛型类,泛型函数,泛型接口。
5.1泛型函数一般格式
返回类型 函数名<输入类型> (参数类型 参数)
{
函数体
}
5.2泛型接口
abstract class Cache<T> {
getByKey(String key);
void setByKey(String key, T value);
}
class MemoryCache<T> implements Cache<T> {
@Override
getByKey(String key){
return null;
}
@Override
void setByKey(String key, T value){
print('文件缓存 key=${key}, value=${value}');
}
}
5.3泛型的上界extends
class Fruit{
}
class Apple extends Fruit{
}
class A<T extends Fruit>{
String toString() => "Instance of 'Fruit<$T>'";
}
6. 枚举
枚举定义
enum Color{red, green, yellow}
枚举的值
List<Color> colors = Color.values;
枚举的索引值
Color.green.index
7. 库
一般用小写+下划线表示一个库
library my_test_lib
7.1库
- 自定义库( import ‘库的位置/库名称.dart’ )
- 系统库(import ‘dart:库名称’)
- 部分引入(import ‘lib/my_test_lib/myfunctions.dart’ show func1, func2)
- 排除引入(import ‘lib/my_test_lib/myfunctions.dart’ hide func1, func2)
- 使用别名解决冲突(import ‘lib/my_test_lib/myfunctions.dart’ as myfunctions)
- 延迟引入(import ‘lib/my_test_lib/myfunctions.dart’ deferred as myfunctions)
7.2 主子库
lib myfunctions
part of myfunctions;
int add(int x, int y){
}
part of myfunctions;
int concat(String a, String b){
}
7.3 自定义库
特定的目录结构,pubspec.yaml
8.Dart内置库-isolate
import 'dart:async';
import 'dart:isolate';
main(List<String> args) {
start();
print("start");
}
Isolate isolate;
int i = 1;
void start() async {
//接收消息的主Isolate的端口
final receive = ReceivePort();
isolate = await Isolate.spawn(runTimer, receive.sendPort);
receive.listen((data) {
print("Reveive : $data ; i :$i");
});
}
void runTimer(SendPort port) {
int counter = 0;
Timer.periodic(const Duration(seconds: 1), (_) {
counter++;
i++;
final msg = "nitification $counter";
print("Send :$msg ;i :$i");
port.send(msg);
});
}
9.Dart原生流Stream
1对1的流(不能同时监听listen):
void main() {
StreamController<String> controller = StreamController<String>();
// controller.stream.listen((item) => print(item));
controller.sink.add("Item1");
controller.sink.add("Item2");
controller.sink.add("Item3");
controller.stream.listen((item) => print("a " + item));
controller.close();
}
运行结果:
[Running] dart "/Users/ouyang/app/flutter/isolate_test/stream.dart"
a Item1
a Item2
a Item3
广播流:
void main() {
StreamController<String> controller = StreamController<String>.broadcast();
controller.stream.listen((item) => print(item));
controller.stream.listen((item) => print("a " + item));
controller.sink.add("Item1");
controller.sink.add("Item2");
controller.sink.add("Item3");
controller.close();
}
运行结果:
Item1
a Item1
Item2
a Item2
Item3
a Item3
10.RxDart
RxDart的开发者阐述他们的设计思想视频(需要翻墙)。里面讲到了如何做类型增强?为何不像其他rx框架封装自己的Observables对象而是选择增强dart原生对象?包括Flutter开发者为什么引入StreamBuilder?它又是如何增强dart原生Stream、StreamController、Subject?
下面表格列出了Observables和Dart的Streams的区别:
既然抛弃了Observables,那么RxDart的作者是如何做到的呢:
- Stream Classes 创建具有特定功能的流,例如将多个流合并在一起。
- Extension Method 将源流转换为具有不同功能的新流,例如节流或缓冲事件
- Subjects 具有额外能力的流控制器
具体细节请看这里